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