@@ -59,7 +59,6 @@ class LiveRange {
59
59
60
60
public:
61
61
LiveRange (SILValue value);
62
-
63
62
LiveRange (const LiveRange &) = delete ;
64
63
LiveRange &operator =(const LiveRange &) = delete ;
65
64
@@ -454,6 +453,7 @@ struct SemanticARCOptVisitor
454
453
455
454
bool performGuaranteedCopyValueOptimization (CopyValueInst *cvi);
456
455
bool eliminateDeadLiveRangeCopyValue (CopyValueInst *cvi);
456
+ bool tryJoiningCopyValueLiveRangeWithOperand (CopyValueInst *cvi);
457
457
};
458
458
459
459
} // end anonymous namespace
@@ -824,13 +824,184 @@ bool SemanticARCOptVisitor::eliminateDeadLiveRangeCopyValue(CopyValueInst *cvi)
824
824
return true ;
825
825
}
826
826
827
+ // Handle simple checking where we do not need to form live ranges and visit a
828
+ // bunch of instructions.
829
+ static bool canSafelyJoinSimpleRange (SILValue cviOperand,
830
+ DestroyValueInst *cviOperandDestroy,
831
+ CopyValueInst *cvi) {
832
+ // We only handle cases where our copy_value has a single consuming use that
833
+ // is not a forwarding use. We need to use the LiveRange functionality to
834
+ // guarantee correctness in the presence of forwarding uses.
835
+ //
836
+ // NOTE: This use may be any type of consuming use and may not be a
837
+ // destroy_value.
838
+ auto *cviConsumer = cvi->getSingleConsumingUse ();
839
+ if (!cviConsumer || isOwnedForwardingInstruction (cviConsumer->getUser ())) {
840
+ return false ;
841
+ }
842
+
843
+ // Ok, we may be able to eliminate this. The main thing we need to be careful
844
+ // of here is that if the destroy_value is /after/ the consuming use of the
845
+ // operand of copy_value, we may have normal uses of the copy_value's operand
846
+ // that would become use-after-frees since we would be shrinking the lifetime
847
+ // of the object potentially. Consider the following SIL:
848
+ //
849
+ // %0 = ...
850
+ // %1 = copy_value %0
851
+ // apply %cviConsumer(%1)
852
+ // apply %guaranteedUser(%0)
853
+ // destroy_value %0
854
+ //
855
+ // Easily, if we were to eliminate the copy_value, destroy_value, the object's
856
+ // lifetime could potentially be shrunk before guaranteedUser is executed,
857
+ // causing guaranteedUser to be a use-after-free.
858
+ //
859
+ // As an extra wrinkle, until all interior pointer constructs (e.x.:
860
+ // project_box) are guaranteed to be guaranted by a begin_borrow, we can not
861
+ // in general safely shrink lifetimes. So even if we think we can prove that
862
+ // all non-consuming uses of %0 are before apply %cviConsumer, we may miss
863
+ // implicit uses that are not guarded yet by a begin_borrow, resulting in
864
+ // use-after-frees.
865
+ //
866
+ // With that in mind, we only handle cases today where we can prove that
867
+ // destroy_value is strictly before the consuming use of the operand. This
868
+ // guarantees that we are not shrinking the lifetime of the underlying object.
869
+ //
870
+ // First we handle the simple case: where the cviConsumer is a return inst. In
871
+ // such a case, we know for sure that cviConsumer post-dominates the
872
+ // destroy_value.
873
+ auto cviConsumerIter = cviConsumer->getUser ()->getIterator ();
874
+ if (isa<ReturnInst>(cviConsumerIter)) {
875
+ return true ;
876
+ }
877
+
878
+ // Then see if our cviConsumer is in the same block as a return inst and the
879
+ // destroy_value is not. In that case, we know that the cviConsumer must
880
+ // post-dominate the destroy_value.
881
+ auto *cviConsumingBlock = cviConsumerIter->getParent ();
882
+ if (isa<ReturnInst>(cviConsumingBlock->getTerminator ()) &&
883
+ cviConsumingBlock != cviOperandDestroy->getParent ()) {
884
+ return true ;
885
+ }
886
+
887
+ // Otherwise, we only support joining live ranges where the cvi and the cvi's
888
+ // operand's destroy are in the same block with the destroy_value of cvi
889
+ // operand needing to be strictly after the copy_value. This analysis can be
890
+ // made significantly stronger by using LiveRanges, but this is simple for
891
+ // now.
892
+ auto cviOperandDestroyIter = cviOperandDestroy->getIterator ();
893
+ if (cviConsumingBlock != cviOperandDestroyIter->getParent ()) {
894
+ return false ;
895
+ }
896
+
897
+ // TODO: This should really be llvm::find, but for some reason, the templates
898
+ // do not match up given the current state of the iterators. This impl works
899
+ // in a pinch though.
900
+ return llvm::any_of (
901
+ llvm::make_range (cviOperandDestroyIter,
902
+ cviOperandDestroyIter->getParent ()->end ()),
903
+ [&](const SILInstruction &val) { return &*cviConsumerIter == &val; });
904
+ }
905
+
906
+ // # The Problem We Are Solving
907
+ //
908
+ // The main idea here is that we are trying to eliminate the simplest, easiest
909
+ // form of live range joining. Consider the following SIL:
910
+ //
911
+ // ```
912
+ // %cviOperand = ... // @owned value
913
+ // %cvi = copy_value %cviOperand // copy of @owned value
914
+ // ...
915
+ // destroy_value %cviOperandDestroy // destruction of @owned value
916
+ // ...
917
+ // apply %consumingUser(%cvi) // destruction of copy of @owned value
918
+ // ```
919
+ //
920
+ // We want to reduce reference count traffic by eliminating the middle
921
+ // copy/destroy yielding:
922
+ //
923
+ // ```
924
+ // %cviOperand = ... // @owned value
925
+ // // *eliminated copy_value*
926
+ // ...
927
+ // // *eliminated destroy_value*
928
+ // ...
929
+ // apply %consumingUser(%cviOperand) // destruction of copy of @owned
930
+ // value
931
+ // ```
932
+ //
933
+ // # Safety
934
+ //
935
+ // In order to do this safely, we need to take the union of the two objects
936
+ // lifetimes since we are only joining lifetimes. This ensures that we can rely
937
+ // on SILGen's correctness on inserting safe lifetimes. To keep this simple
938
+ // today we only optimize if the destroy_value and consuming user are in the
939
+ // same block and the consuming user is later in the block than the
940
+ // destroy_value.
941
+ //
942
+ // DISCUSSION: The reason why we do not shrink lifetimes today is that all
943
+ // interior pointers (e.x. project_box) are properly guarded by
944
+ // begin_borrow. Because of that we can not shrink lifetimes and instead rely on
945
+ // SILGen's correctness.
946
+ bool SemanticARCOptVisitor::tryJoiningCopyValueLiveRangeWithOperand (
947
+ CopyValueInst *cvi) {
948
+ // First do a quick check if our operand is owned. If it is not owned, we can
949
+ // not join live ranges.
950
+ SILValue operand = cvi->getOperand ();
951
+ if (operand.getOwnershipKind () != ValueOwnershipKind::Owned) {
952
+ return false ;
953
+ }
954
+
955
+ // Then check if our operand has a single destroy_value. If it does and that
956
+ // destroy_value is strictly before the consumer of our copy_value in the same
957
+ // block as the consumer of said copy_value then we can always join the live
958
+ // ranges.
959
+ //
960
+ // Example:
961
+ //
962
+ // ```
963
+ // %1 = copy_value %0
964
+ // ...
965
+ // destroy_value %0
966
+ // apply %consumingUser(%1)
967
+ // ```
968
+ // ->
969
+ //
970
+ // ```
971
+ // apply %consumingUser(%0)
972
+ // ```
973
+ //
974
+ // DISCUSSION: We need to ensure that the consuming use of the copy_value is
975
+ // strictly after the destroy_value to ensure that we do not shrink the live
976
+ // range of the operand if the operand has any normal uses beyond our copy
977
+ // value. Otherwise, we could have normal uses /after/ the consuming use of
978
+ // our copy_value.
979
+ if (auto *dvi = operand->getSingleConsumingUserOfType <DestroyValueInst>()) {
980
+ if (canSafelyJoinSimpleRange (operand, dvi, cvi)) {
981
+ eraseInstruction (dvi);
982
+ eraseAndRAUWSingleValueInstruction (cvi, operand);
983
+ NumEliminatedInsts += 2 ;
984
+ return true ;
985
+ }
986
+ }
987
+
988
+ // Otherwise, we couldn't handle this case, so return false.
989
+ return false ;
990
+ }
991
+
827
992
bool SemanticARCOptVisitor::visitCopyValueInst (CopyValueInst *cvi) {
828
993
// If our copy value inst has only destroy_value users, it is a dead live
829
994
// range. Try to eliminate them.
830
995
if (eliminateDeadLiveRangeCopyValue (cvi)) {
831
996
return true ;
832
997
}
833
998
999
+ // Then see if copy_value operand's lifetime ends after our copy_value via a
1000
+ // destroy_value. If so, we can join their lifetimes.
1001
+ if (tryJoiningCopyValueLiveRangeWithOperand (cvi)) {
1002
+ return true ;
1003
+ }
1004
+
834
1005
// Then try to perform the guaranteed copy value optimization.
835
1006
if (performGuaranteedCopyValueOptimization (cvi)) {
836
1007
return true ;
0 commit comments