@@ -61,17 +61,30 @@ static bool isRelease(SILInstruction *I) {
61
61
}
62
62
}
63
63
64
+ // / Returns true if LHS and RHS contain identical set of releases.
65
+ static bool hasIdenticalReleases (ReleaseList LHS, ReleaseList RHS) {
66
+ llvm::DenseSet<SILInstruction *> Releases;
67
+ if (LHS.size () != RHS.size ())
68
+ return false ;
69
+ for (auto &X : LHS)
70
+ Releases.insert (X);
71
+ for (auto &X : RHS)
72
+ if (Releases.find (X) == Releases.end ())
73
+ return false ;
74
+ return true ;
75
+ }
76
+
64
77
// / Returns .Some(I) if I is a release that is the only non-debug instruction
65
78
// / with side-effects in the use-def graph originating from Arg. Returns
66
79
// / .Some(nullptr), if all uses from the arg were either debug insts or do not
67
80
// / have side-effects. Returns .None if there were any non-release instructions
68
81
// / with side-effects in the use-def graph from Arg or if there were multiple
69
82
// / release instructions with side-effects in the use-def graph from Arg.
70
- static llvm::Optional<NullablePtr<SILInstruction> >
83
+ static llvm::Optional<ReleaseList >
71
84
getNonTrivialNonDebugReleaseUse (SILArgument *Arg) {
72
85
llvm::SmallVector<SILInstruction *, 8 > Worklist;
73
86
llvm::SmallPtrSet<SILInstruction *, 8 > SeenInsts;
74
- llvm::Optional<SILInstruction *> Result;
87
+ ReleaseList Result;
75
88
76
89
for (Operand *I : getNonDebugUses (SILValue (Arg)))
77
90
Worklist.push_back (I->getUser ());
@@ -91,12 +104,8 @@ getNonTrivialNonDebugReleaseUse(SILArgument *Arg) {
91
104
if (!isRelease (U))
92
105
return None;
93
106
94
- // If we have already seen a release of some sort, bail.
95
- if (Result.hasValue ())
96
- return None;
97
-
98
107
// Otherwise, set result to that value.
99
- Result = U ;
108
+ Result. push_back (U) ;
100
109
continue ;
101
110
}
102
111
@@ -105,9 +114,7 @@ getNonTrivialNonDebugReleaseUse(SILArgument *Arg) {
105
114
Worklist.push_back (I->getUser ());
106
115
}
107
116
108
- if (!Result.hasValue ())
109
- return NullablePtr<SILInstruction>();
110
- return NullablePtr<SILInstruction>(Result.getValue ());
117
+ return Result;
111
118
}
112
119
113
120
// ===----------------------------------------------------------------------===//
@@ -138,11 +145,11 @@ struct ArgumentDescriptor {
138
145
// / If non-null, this is the release in the return block of the callee, which
139
146
// / is associated with this parameter if it is @owned. If the parameter is not
140
147
// / @owned or we could not find such a release in the callee, this is null.
141
- SILInstruction * CalleeRelease;
148
+ ReleaseList CalleeRelease;
142
149
143
150
// / The same as CalleeRelease, but the release in the throw block, if it is a
144
151
// / function which has a throw block.
145
- SILInstruction * CalleeReleaseInThrowBlock;
152
+ ReleaseList CalleeReleaseInThrowBlock;
146
153
147
154
// / The projection tree of this arguments.
148
155
ProjectionTree ProjTree;
@@ -239,9 +246,9 @@ void ArgumentDescriptor::computeOptimizedInterfaceParams(
239
246
// If we cannot explode this value, handle callee release and return.
240
247
if (!shouldExplode ()) {
241
248
DEBUG (llvm::dbgs () << " ProjTree cannot explode arg.\n " );
242
- // If we found a release in the callee in the last BB on an @owned
249
+ // If we found releases in the callee in the last BB on an @owned
243
250
// parameter, change the parameter to @guaranteed and continue...
244
- if (CalleeRelease) {
251
+ if (! CalleeRelease. empty () ) {
245
252
DEBUG (llvm::dbgs () << " Has callee release.\n " );
246
253
assert (ParameterInfo.getConvention () ==
247
254
ParameterConvention::Direct_Owned &&
@@ -277,8 +284,8 @@ void ArgumentDescriptor::computeOptimizedInterfaceParams(
277
284
// If Ty is guaranteed, just pass it through.
278
285
ParameterConvention Conv = ParameterInfo.getConvention ();
279
286
if (Conv == ParameterConvention::Direct_Guaranteed) {
280
- assert (! CalleeRelease && " Guaranteed parameter should not have a callee "
281
- " release." );
287
+ assert (CalleeRelease. empty () && " Guaranteed parameter should not have a "
288
+ " callee release." );
282
289
SILParameterInfo NewInfo (Ty.getSwiftRValueType (),
283
290
ParameterConvention::Direct_Guaranteed);
284
291
Out.push_back (NewInfo);
@@ -289,7 +296,7 @@ void ArgumentDescriptor::computeOptimizedInterfaceParams(
289
296
// guaranteed.
290
297
assert (ParameterInfo.getConvention () == ParameterConvention::Direct_Owned &&
291
298
" Can only transform @owned => @guaranteed in this code path" );
292
- if (CalleeRelease) {
299
+ if (! CalleeRelease. empty () ) {
293
300
SILParameterInfo NewInfo (Ty.getSwiftRValueType (),
294
301
ParameterConvention::Direct_Guaranteed);
295
302
Out.push_back (NewInfo);
@@ -344,16 +351,10 @@ unsigned ArgumentDescriptor::updateOptimizedBBArgs(SILBuilder &Builder,
344
351
// do need the instruction to be non-null.
345
352
//
346
353
// TODO: This should not be necessary.
347
- if ( CalleeRelease) {
348
- SILType CalleeReleaseTy = CalleeRelease ->getOperand (0 )->getType ();
349
- CalleeRelease ->setOperand (
354
+ for ( auto &X : CalleeRelease) {
355
+ SILType CalleeReleaseTy = X ->getOperand (0 )->getType ();
356
+ X ->setOperand (
350
357
0 , SILUndef::get (CalleeReleaseTy, Builder.getModule ()));
351
-
352
- // TODO: Currently we cannot mark arguments as dead if they are released
353
- // in a throw block. But as soon as we can do this, we have to handle
354
- // CalleeReleaseInThrowBlock as well.
355
- assert (!CalleeReleaseInThrowBlock &&
356
- " released arg in throw block cannot be dead" );
357
358
}
358
359
359
360
// We should be able to recursively delete all of the remaining
@@ -533,7 +534,7 @@ bool ParameterAnalyzer::analyze() {
533
534
534
535
// If this argument is not ABI required and has no uses except for debug
535
536
// instructions, remove it.
536
- if (!isABIRequired && OnlyRelease && OnlyRelease.getValue ().isNull ()) {
537
+ if (!isABIRequired && OnlyRelease && OnlyRelease.getValue ().empty ()) {
537
538
A.IsDead = true ;
538
539
HaveOptimizedArg = true ;
539
540
++NumDeadArgsEliminated;
@@ -542,21 +543,22 @@ bool ParameterAnalyzer::analyze() {
542
543
// See if we can find a ref count equivalent strong_release or release_value
543
544
// at the end of this function if our argument is an @owned parameter.
544
545
if (A.hasConvention (ParameterConvention::Direct_Owned)) {
545
- if ( auto *Release = ArgToReturnReleaseMap.getSingleReleaseForArgument (A.Arg )) {
546
- SILInstruction *ReleaseInThrow = nullptr ;
546
+ auto Releases = ArgToReturnReleaseMap.getReleasesForArgument (A.Arg );
547
+ if (!Releases. empty ()) {
547
548
548
549
// If the function has a throw block we must also find a matching
549
550
// release in the throw block.
550
- if (! ArgToThrowReleaseMap.hasBlock () ||
551
- (ReleaseInThrow = ArgToThrowReleaseMap.getSingleReleaseForArgument (A. Arg ) )) {
551
+ auto ReleasesInThrow = ArgToThrowReleaseMap.getReleasesForArgument (A. Arg );
552
+ if (! ArgToThrowReleaseMap.hasBlock () || !ReleasesInThrow. empty ( )) {
552
553
553
554
// TODO: accept a second release in the throw block to let the
554
555
// argument be dead.
555
- if (OnlyRelease && OnlyRelease.getValue (). getPtrOrNull () == Release ) {
556
+ if (OnlyRelease && hasIdenticalReleases ( OnlyRelease.getValue (), Releases) ) {
556
557
A.IsDead = true ;
557
558
}
558
- A.CalleeRelease = Release;
559
- A.CalleeReleaseInThrowBlock = ReleaseInThrow;
559
+
560
+ A.CalleeRelease = Releases;
561
+ A.CalleeReleaseInThrowBlock = ReleasesInThrow;
560
562
HaveOptimizedArg = true ;
561
563
++NumOwnedConvertedToGuaranteed;
562
564
}
@@ -600,7 +602,7 @@ std::string ParameterAnalyzer::getOptimizedName() const {
600
602
601
603
// If we have an @owned argument and found a callee release for it,
602
604
// convert the argument to guaranteed.
603
- if (Arg.CalleeRelease ) {
605
+ if (! Arg.CalleeRelease . empty () ) {
604
606
FSSM.setArgumentOwnedToGuaranteed (i);
605
607
}
606
608
@@ -721,7 +723,7 @@ static void rewriteApplyInstToCallNewFunction(SignatureOptimizer &Optimizer,
721
723
// If we have any arguments that were consumed but are now guaranteed,
722
724
// insert a release_value in the error block.
723
725
for (auto &ArgDesc : ArgDescs) {
724
- if (! ArgDesc.CalleeRelease )
726
+ if (ArgDesc.CalleeRelease . empty () )
725
727
continue ;
726
728
Builder.createReleaseValue (Loc, FAS.getArgument (ArgDesc.Index ));
727
729
}
@@ -733,7 +735,7 @@ static void rewriteApplyInstToCallNewFunction(SignatureOptimizer &Optimizer,
733
735
// If we have any arguments that were consumed but are now guaranteed,
734
736
// insert a release_value.
735
737
for (auto &ArgDesc : ArgDescs) {
736
- if (! ArgDesc.CalleeRelease )
738
+ if (ArgDesc.CalleeRelease . empty () )
737
739
continue ;
738
740
Builder.createReleaseValue (Loc, FAS.getArgument (ArgDesc.Index ));
739
741
}
@@ -784,7 +786,7 @@ static void createThunkBody(SILBasicBlock *BB, SILFunction *NewF,
784
786
// insert a release_value in the error block.
785
787
Builder.setInsertionPoint (ErrorBlock);
786
788
for (auto &ArgDesc : ArgDescs) {
787
- if (! ArgDesc.CalleeRelease )
789
+ if (ArgDesc.CalleeRelease . empty () )
788
790
continue ;
789
791
Builder.createReleaseValue (Loc, BB->getBBArg (ArgDesc.Index ));
790
792
}
@@ -801,7 +803,7 @@ static void createThunkBody(SILBasicBlock *BB, SILFunction *NewF,
801
803
// If we have any arguments that were consumed but are now guaranteed,
802
804
// insert a release_value.
803
805
for (auto &ArgDesc : ArgDescs) {
804
- if (! ArgDesc.CalleeRelease )
806
+ if (ArgDesc.CalleeRelease . empty () )
805
807
continue ;
806
808
Builder.createReleaseValue (Loc, BB->getBBArg (ArgDesc.Index ));
807
809
}
@@ -911,12 +913,10 @@ static bool optimizeFunctionSignature(llvm::BumpPtrAllocator &BPA,
911
913
//
912
914
// TODO: If more stuff needs to be placed here, refactor into its own method.
913
915
for (auto &A : Optimizer.getArgDescList ()) {
914
- if (A.CalleeRelease ) {
915
- A.CalleeRelease ->eraseFromParent ();
916
- if (A.CalleeReleaseInThrowBlock ) {
917
- A.CalleeReleaseInThrowBlock ->eraseFromParent ();
918
- }
919
- }
916
+ for (auto &X : A.CalleeRelease )
917
+ X->eraseFromParent ();
918
+ for (auto &X : A.CalleeReleaseInThrowBlock )
919
+ X->eraseFromParent ();
920
920
}
921
921
922
922
// Rewrite all apply insts calling F to call NewF. Update each call site as
0 commit comments