83
83
#include " swift/SIL/BasicBlockUtils.h"
84
84
#include " swift/SIL/CFG.h"
85
85
#include " swift/SIL/InstructionUtils.h"
86
+ #include " swift/SIL/OwnershipUtils.h"
86
87
#include " swift/SIL/SILBasicBlock.h"
87
88
#include " swift/SIL/SILBuilder.h"
88
89
#include " swift/SIL/SILConstants.h"
@@ -511,7 +512,6 @@ static SILValue emitCodeForConstantArray(ArrayRef<SILValue> elements,
511
512
assert (astContext.getArrayDecl () ==
512
513
arrayType->getNominalOrBoundGenericNominal ());
513
514
SILModule &module = builder.getModule ();
514
- SILFunction &fun = builder.getFunction ();
515
515
516
516
// Create a SILValue for the number of elements.
517
517
unsigned numElements = elements.size ();
@@ -539,19 +539,10 @@ static SILValue emitCodeForConstantArray(ArrayRef<SILValue> elements,
539
539
loc, arrayAllocateRef, subMap, ArrayRef<SILValue>(numElementsSIL), false );
540
540
541
541
// Extract the elements of the tuple returned by the call to the allocator.
542
- SILValue arraySIL;
543
- SILValue storagePointerSIL;
544
- if (fun.hasOwnership ()) {
545
- DestructureTupleInst *destructureInst =
546
- builder.createDestructureTuple (loc, applyInst);
547
- arraySIL = destructureInst->getResults ()[0 ];
548
- storagePointerSIL = destructureInst->getResults ()[1 ];
549
- } else {
550
- SILType arraySILType = SILType::getPrimitiveObjectType (arrayType);
551
- arraySIL = builder.createTupleExtract (loc, applyInst, 0 , arraySILType);
552
- storagePointerSIL = builder.createTupleExtract (
553
- loc, applyInst, 1 , SILType::getRawPointerType (astContext));
554
- }
542
+ DestructureTupleInst *destructureInst =
543
+ builder.createDestructureTuple (loc, applyInst);
544
+ SILValue arraySIL = destructureInst->getResults ()[0 ];
545
+ SILValue storagePointerSIL = destructureInst->getResults ()[1 ];
555
546
556
547
if (elements.empty ()) {
557
548
// Nothing more to be done if we are creating an empty array.
@@ -847,20 +838,21 @@ getEndPointsOfDataDependentChain(SILValue value, SILFunction *fun,
847
838
}
848
839
}
849
840
850
- // / Given an instruction \p inst, invoke the given clean-up function \p cleanup
851
- // / on its lifetime frontier, which are instructions that follow the last use of
852
- // / the results of \c inst. E.g. the clean-up function could destory/release
853
- // / the function result.
854
- static void
855
- cleanupAtEndOfLifetime (SILInstruction *inst,
856
- llvm::function_ref<void (SILInstruction *)> cleanup) {
857
- ValueLifetimeAnalysis lifetimeAnalysis = ValueLifetimeAnalysis (inst);
858
- ValueLifetimeAnalysis::Frontier frontier;
859
- (void )lifetimeAnalysis.computeFrontier (
860
- frontier, ValueLifetimeAnalysis::AllowToModifyCFG);
861
- for (SILInstruction *lifetimeEndInst : frontier) {
862
- cleanup (lifetimeEndInst);
863
- }
841
+ // / Given a guaranteed SILValue \p value, return a borrow-scope introducing
842
+ // / value, if there is exactly one such introducing value. Otherwise, return
843
+ // / None. There can be multiple borrow scopes for a SILValue iff it is derived
844
+ // / from a guaranteed basic block parameter representing a phi node.
845
+ static Optional<BorrowScopeIntroducingValue>
846
+ getUniqueBorrowScopeIntroducingValue (SILValue value) {
847
+ assert (value.getOwnershipKind () == ValueOwnershipKind::Guaranteed &&
848
+ " parameter must be a guarenteed value" );
849
+ SmallVector<BorrowScopeIntroducingValue, 4 > borrowIntroducers;
850
+ getUnderlyingBorrowIntroducingValues (value, borrowIntroducers);
851
+ assert (borrowIntroducers.size () > 0 &&
852
+ " folding guaranteed value with no borrow introducer" );
853
+ if (borrowIntroducers.size () > 1 )
854
+ return None;
855
+ return borrowIntroducers[0 ];
864
856
}
865
857
866
858
// / Replace all uses of \c originalVal by \c foldedVal and adjust lifetimes of
@@ -889,45 +881,7 @@ static void replaceAllUsesAndFixLifetimes(SILValue foldedVal,
889
881
return ;
890
882
}
891
883
assert (!foldedVal->getType ().isTrivial (*fun));
892
-
893
- if (!fun->hasOwnership ()) {
894
- // In non-ownership SIL, handle only folding of struct_extract instruction,
895
- // which is the only important instruction that should be folded by this
896
- // pass. The logic used here is not correct in general and overfits a
897
- // specific form of SIL. This code should be removed once OSSA is enabled
898
- // for this pass.
899
- // TODO: this code can be safely removed once ownership SIL becomes the
900
- // default SIL this pass works on.
901
- assert (isa<StructExtractInst>(originalInst) &&
902
- !originalVal->getType ().isAddress ());
903
-
904
- // First, replace all uses of originalVal by foldedVal, and then adjust
905
- // their lifetimes if necessary.
906
- originalVal->replaceAllUsesWith (foldedVal);
907
-
908
- unsigned retainCount = 0 ;
909
- unsigned consumeCount = 0 ;
910
- for (Operand *use : foldedVal->getUses ()) {
911
- SILInstruction *user = use->getUser ();
912
- if (isa<ReleaseValueInst>(user) || isa<StoreInst>(user))
913
- consumeCount++;
914
- if (isa<RetainValueInst>(user))
915
- retainCount++;
916
- // Note that there could other consuming operations but they are not
917
- // handled here as this code should be phased out soon.
918
- }
919
- if (consumeCount > retainCount) {
920
- // The original value was at +1 and therefore consumed at the end. Since
921
- // the foldedVal is also at +1 there is nothing to be done.
922
- return ;
923
- }
924
- cleanupAtEndOfLifetime (foldedInst, [&](SILInstruction *lifetimeEndInst) {
925
- SILBuilderWithScope builder (lifetimeEndInst);
926
- builder.emitReleaseValue (lifetimeEndInst->getLoc (), foldedVal);
927
- });
928
- return ;
929
- }
930
-
884
+ assert (fun->hasOwnership ());
931
885
assert (foldedVal.getOwnershipKind () == ValueOwnershipKind::Owned &&
932
886
" constant value must have owned ownership kind" );
933
887
@@ -943,22 +897,36 @@ static void replaceAllUsesAndFixLifetimes(SILValue foldedVal,
943
897
return ;
944
898
}
945
899
946
- // Here, originalVal is not owned. Hence, borrow form foldedVal and use the
947
- // borrow in place of originalVal. Also, destroy foldedVal at the end of its
948
- // lifetime.
900
+ // Here, originalVal is guaranteed. It must belong to a borrow scope that
901
+ // begins at a scope introducing instruction e.g. begin_borrow or load_borrow.
902
+ // The foldedVal should also have been inserted at the beginning of the scope.
903
+ // Therefore, create a borrow of foldedVal at the beginning of the scope and
904
+ // use the borrow in place of the originalVal. Also, end the borrow and
905
+ // destroy foldedVal at the end of the borrow scope.
949
906
assert (originalVal.getOwnershipKind () == ValueOwnershipKind::Guaranteed);
950
907
951
- SILBuilderWithScope builder (&*std::next (foldedInst->getIterator ()));
952
- BeginBorrowInst *borrow =
953
- builder.createBeginBorrow (foldedInst->getLoc (), foldedVal);
908
+ Optional<BorrowScopeIntroducingValue> originalScopeBegin =
909
+ getUniqueBorrowScopeIntroducingValue (originalVal);
910
+ assert (originalScopeBegin &&
911
+ " value without a unique borrow scope should not have been folded" );
912
+ SILInstruction *scopeBeginInst =
913
+ originalScopeBegin->value ->getDefiningInstruction ();
914
+ assert (scopeBeginInst);
915
+
916
+ SILBuilderWithScope builder (scopeBeginInst);
917
+ SILValue borrow =
918
+ builder.emitBeginBorrowOperation (scopeBeginInst->getLoc (), foldedVal);
954
919
955
920
originalVal->replaceAllUsesWith (borrow);
956
921
957
- cleanupAtEndOfLifetime (borrow, [&](SILInstruction *lifetimeEndInst) {
958
- SILBuilderWithScope builder (lifetimeEndInst);
959
- builder.createEndBorrow (lifetimeEndInst->getLoc (), borrow);
960
- builder.emitDestroyValueOperation (lifetimeEndInst->getLoc (), foldedVal);
961
- });
922
+ SmallVector<SILInstruction *, 4 > scopeEndingInsts;
923
+ originalScopeBegin->getLocalScopeEndingInstructions (scopeEndingInsts);
924
+
925
+ for (SILInstruction *scopeEndingInst : scopeEndingInsts) {
926
+ SILBuilderWithScope builder (scopeEndingInst);
927
+ builder.emitEndBorrowOperation (scopeEndingInst->getLoc (), borrow);
928
+ builder.emitDestroyValueOperation (scopeEndingInst->getLoc (), foldedVal);
929
+ }
962
930
return ;
963
931
}
964
932
@@ -978,13 +946,31 @@ static void substituteConstants(FoldState &foldState) {
978
946
assert (definingInst);
979
947
SILFunction *fun = definingInst->getFunction ();
980
948
981
- // Do not attempt to fold anything but struct_extract in non-OSSA.
982
- // TODO: this condition should be removed once migration OSSA is complete.
983
- if (!fun->hasOwnership () && !isa<StructExtractInst>(definingInst))
984
- continue ;
949
+ // Find an insertion point for inserting the new constant value. If we are
950
+ // folding a value like struct_extract within a borrow scope, we need to
951
+ // insert the constant value at the beginning of the borrow scope. This
952
+ // is because the borrowed value is expected to be alive during its entire
953
+ // borrow scope and could be stored into memory and accessed indirectly
954
+ // without a copy e.g. using store_borrow within the borrow scope. On the
955
+ // other hand, if we are folding an owned value, we can insert the constant
956
+ // value at the point where the owned value is defined.
957
+ SILInstruction *insertionPoint = definingInst;
958
+ if (constantSILValue.getOwnershipKind () == ValueOwnershipKind::Guaranteed) {
959
+ Optional<BorrowScopeIntroducingValue> borrowIntroducer =
960
+ getUniqueBorrowScopeIntroducingValue (constantSILValue);
961
+ if (!borrowIntroducer) {
962
+ // This case happens only if constantSILValue is derived from a
963
+ // guaranteed basic block parameter. This is unlikley because the values
964
+ // that have to be folded should just be a struct-extract of an owned
965
+ // instance of OSLogMessage.
966
+ continue ;
967
+ }
968
+ insertionPoint = borrowIntroducer->value ->getDefiningInstruction ();
969
+ assert (insertionPoint && " borrow scope begnning is a parameter" );
970
+ }
985
971
986
- SILBuilderWithScope builder (definingInst );
987
- SILLocation loc = definingInst ->getLoc ();
972
+ SILBuilderWithScope builder (insertionPoint );
973
+ SILLocation loc = insertionPoint ->getLoc ();
988
974
CanType instType = constantSILValue->getType ().getASTType ();
989
975
SILValue foldedSILVal = emitCodeForSymbolicValue (
990
976
constantSymbolicVal, instType, builder, loc, foldState.stringInfo );
@@ -1068,6 +1054,7 @@ static bool constantFold(SILInstruction *start,
1068
1054
SingleValueInstruction *oslogMessage,
1069
1055
unsigned assertConfig) {
1070
1056
SILFunction *fun = start->getFunction ();
1057
+ assert (fun->hasOwnership () && " function not in ownership SIL" );
1071
1058
1072
1059
// Initialize fold state.
1073
1060
SmallVector<SILInstruction *, 2 > endUsersOfOSLogMessage;
0 commit comments