26
26
#include " swift/SILOptimizer/PassManager/Passes.h"
27
27
#include " swift/SILOptimizer/PassManager/Transforms.h"
28
28
#include " swift/SILOptimizer/Utils/InstOptUtils.h"
29
+ #include " swift/SILOptimizer/Utils/ValueLifetime.h"
29
30
#include " llvm/ADT/SmallPtrSet.h"
30
31
#include " llvm/ADT/SmallVector.h"
31
32
#include " llvm/ADT/Statistic.h"
@@ -45,9 +46,9 @@ STATISTIC(NumLoadCopyConvertedToLoadBorrow,
45
46
// /
46
47
// / Semantically this implies that a value is never passed off as +1 to memory
47
48
// / or another function implying it can be used everywhere at +0.
48
- static bool isDeadLiveRange (
49
- SILValue v, SmallVectorImpl<DestroyValueInst *> &destroys,
50
- NullablePtr< SmallVectorImpl<SILInstruction *>> forwardingInsts = nullptr ) {
49
+ static bool
50
+ isDeadLiveRange ( SILValue v, SmallVectorImpl<SILInstruction *> &destroys,
51
+ SmallVectorImpl<SILInstruction *> & forwardingInsts) {
51
52
assert (v.getOwnershipKind () == ValueOwnershipKind::Owned);
52
53
SmallVector<Operand *, 32 > worklist (v->use_begin (), v->use_end ());
53
54
while (!worklist.empty ()) {
@@ -85,8 +86,7 @@ static bool isDeadLiveRange(
85
86
//
86
87
// NOTE: Today we do not support TermInsts for simplicity... we /could/
87
88
// support it though if we need to.
88
- if (forwardingInsts.isNull () || isa<TermInst>(user) ||
89
- !isGuaranteedForwardingInst (user) ||
89
+ if (isa<TermInst>(user) || !isGuaranteedForwardingInst (user) ||
90
90
1 != count_if (user->getOperandValues (
91
91
true /* ignore type dependent operands*/ ),
92
92
[&](SILValue v) {
@@ -99,7 +99,7 @@ static bool isDeadLiveRange(
99
99
// Ok, this is a forwarding instruction whose ownership we can flip from
100
100
// owned -> guaranteed. Visit its users recursively to see if the the
101
101
// users force the live range to be alive.
102
- forwardingInsts.get ()-> push_back (user);
102
+ forwardingInsts.push_back (user);
103
103
for (SILValue v : user->getResults ()) {
104
104
if (v.getOwnershipKind () != ValueOwnershipKind::Owned)
105
105
continue ;
@@ -158,6 +158,7 @@ struct SemanticARCOptVisitor
158
158
159
159
SILFunction &F;
160
160
Optional<DeadEndBlocks> TheDeadEndBlocks;
161
+ ValueLifetimeAnalysis::Frontier lifetimeFrontier;
161
162
162
163
explicit SemanticARCOptVisitor (SILFunction &F) : F(F) {}
163
164
@@ -370,6 +371,49 @@ bool SemanticARCOptVisitor::visitBeginBorrowInst(BeginBorrowInst *bbi) {
370
371
return true ;
371
372
}
372
373
374
+ static void convertForwardingInstsFromOwnedToGuaranteed (
375
+ SmallVectorImpl<SILInstruction *> &guaranteedForwardingInsts) {
376
+ // Then change all of our guaranteed forwarding insts to have guaranteed
377
+ // ownership kind instead of what ever they previously had (ignoring trivial
378
+ // results);
379
+ while (!guaranteedForwardingInsts.empty ()) {
380
+ auto *i = guaranteedForwardingInsts.pop_back_val ();
381
+ assert (i->hasResults ());
382
+
383
+ for (SILValue result : i->getResults ()) {
384
+ if (auto *svi = dyn_cast<OwnershipForwardingSingleValueInst>(result)) {
385
+ if (svi->getOwnershipKind () == ValueOwnershipKind::Owned) {
386
+ svi->setOwnershipKind (ValueOwnershipKind::Guaranteed);
387
+ }
388
+ continue ;
389
+ }
390
+
391
+ if (auto *ofci = dyn_cast<OwnershipForwardingConversionInst>(result)) {
392
+ if (ofci->getOwnershipKind () == ValueOwnershipKind::Owned) {
393
+ ofci->setOwnershipKind (ValueOwnershipKind::Guaranteed);
394
+ }
395
+ continue ;
396
+ }
397
+
398
+ if (auto *sei = dyn_cast<OwnershipForwardingSelectEnumInstBase>(result)) {
399
+ if (sei->getOwnershipKind () == ValueOwnershipKind::Owned) {
400
+ sei->setOwnershipKind (ValueOwnershipKind::Guaranteed);
401
+ }
402
+ continue ;
403
+ }
404
+
405
+ if (auto *mvir = dyn_cast<MultipleValueInstructionResult>(result)) {
406
+ if (mvir->getOwnershipKind () == ValueOwnershipKind::Owned) {
407
+ mvir->setOwnershipKind (ValueOwnershipKind::Guaranteed);
408
+ }
409
+ continue ;
410
+ }
411
+
412
+ llvm_unreachable (" unhandled forwarding instruction?!" );
413
+ }
414
+ }
415
+ }
416
+
373
417
// Eliminate a copy of a borrowed value, if:
374
418
//
375
419
// 1. All of the copies users do not consume the copy (and thus can accept a
@@ -417,9 +461,9 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
417
461
// must be some consuming use that we either do not understand is /actually/
418
462
// forwarding or a user that truly represents a necessary consume of the
419
463
// value (e.x. storing into memory).
420
- SmallVector<DestroyValueInst *, 16 > destroys;
464
+ SmallVector<SILInstruction *, 16 > destroys;
421
465
SmallVector<SILInstruction *, 16 > guaranteedForwardingInsts;
422
- if (!isDeadLiveRange (cvi, destroys, & guaranteedForwardingInsts))
466
+ if (!isDeadLiveRange (cvi, destroys, guaranteedForwardingInsts))
423
467
return false ;
424
468
425
469
// Next check if we do not have any destroys of our copy_value and are
@@ -530,47 +574,8 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
530
574
}
531
575
532
576
eraseAndRAUWSingleValueInstruction (cvi, cvi->getOperand ());
577
+ convertForwardingInstsFromOwnedToGuaranteed (guaranteedForwardingInsts);
533
578
534
- // Then change all of our guaranteed forwarding insts to have guaranteed
535
- // ownership kind instead of what ever they previously had (ignoring trivial
536
- // results);
537
- while (!guaranteedForwardingInsts.empty ()) {
538
- auto *i = guaranteedForwardingInsts.pop_back_val ();
539
-
540
- assert (i->hasResults ());
541
-
542
- for (SILValue result : i->getResults ()) {
543
- if (auto *svi = dyn_cast<OwnershipForwardingSingleValueInst>(result)) {
544
- if (svi->getOwnershipKind () == ValueOwnershipKind::Owned) {
545
- svi->setOwnershipKind (ValueOwnershipKind::Guaranteed);
546
- }
547
- continue ;
548
- }
549
-
550
- if (auto *ofci = dyn_cast<OwnershipForwardingConversionInst>(result)) {
551
- if (ofci->getOwnershipKind () == ValueOwnershipKind::Owned) {
552
- ofci->setOwnershipKind (ValueOwnershipKind::Guaranteed);
553
- }
554
- continue ;
555
- }
556
-
557
- if (auto *sei = dyn_cast<OwnershipForwardingSelectEnumInstBase>(result)) {
558
- if (sei->getOwnershipKind () == ValueOwnershipKind::Owned) {
559
- sei->setOwnershipKind (ValueOwnershipKind::Guaranteed);
560
- }
561
- continue ;
562
- }
563
-
564
- if (auto *mvir = dyn_cast<MultipleValueInstructionResult>(result)) {
565
- if (mvir->getOwnershipKind () == ValueOwnershipKind::Owned) {
566
- mvir->setOwnershipKind (ValueOwnershipKind::Guaranteed);
567
- }
568
- continue ;
569
- }
570
-
571
- llvm_unreachable (" unhandled forwarding instruction?!" );
572
- }
573
- }
574
579
++NumEliminatedInsts;
575
580
return true ;
576
581
}
@@ -812,8 +817,9 @@ bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) {
812
817
// FIXME: We should consider if it is worth promoting a load [copy]
813
818
// -> load_borrow if we can put a copy_value on a cold path and thus
814
819
// eliminate RR traffic on a hot path.
815
- SmallVector<DestroyValueInst *, 32 > destroyValues;
816
- if (!isDeadLiveRange (li, destroyValues))
820
+ SmallVector<SILInstruction *, 32 > destroyValues;
821
+ SmallVector<SILInstruction *, 16 > guaranteedForwardingInsts;
822
+ if (!isDeadLiveRange (li, destroyValues, guaranteedForwardingInsts))
817
823
return false ;
818
824
819
825
// Then check if our address is ever written to. If it is, then we cannot use
@@ -831,14 +837,34 @@ bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) {
831
837
// parameters, we can have multiple destroy_value along the same path. We need
832
838
// to find the post-dominating block set of these destroy value to ensure that
833
839
// we do not insert multiple end_borrow.
840
+ assert (lifetimeFrontier.empty ());
841
+ ValueLifetimeAnalysis analysis (li, destroyValues);
842
+ bool foundCriticalEdges = !analysis.computeFrontier (
843
+ lifetimeFrontier, ValueLifetimeAnalysis::DontModifyCFG,
844
+ &getDeadEndBlocks ());
845
+ (void )foundCriticalEdges;
846
+ assert (!foundCriticalEdges);
847
+ auto loc = RegularLocation::getAutoGeneratedLocation ();
848
+ while (!lifetimeFrontier.empty ()) {
849
+ auto *insertPoint = lifetimeFrontier.pop_back_val ();
850
+ SILBuilderWithScope builder (insertPoint);
851
+ builder.createEndBorrow (loc, lbi);
852
+ }
853
+
854
+ // Then delete all of our destroy_value.
834
855
while (!destroyValues.empty ()) {
835
856
auto *dvi = destroyValues.pop_back_val ();
836
- SILBuilderWithScope (dvi).createEndBorrow (dvi->getLoc (), lbi);
837
857
eraseInstruction (dvi);
838
858
++NumEliminatedInsts;
839
859
}
840
860
861
+ // RAUW our other uses from the load to the load_borrow.
841
862
eraseAndRAUWSingleValueInstruction (li, lbi);
863
+
864
+ // And then change the ownership all of our owned forwarding users to be
865
+ // guaranteed.
866
+ convertForwardingInstsFromOwnedToGuaranteed (guaranteedForwardingInsts);
867
+
842
868
++NumEliminatedInsts;
843
869
++NumLoadCopyConvertedToLoadBorrow;
844
870
return true ;
0 commit comments