Skip to content

Commit ee79f06

Browse files
committed
[func-sig-opts] Extract out rest of helper functions from FunctionSignatureTransform in preparation for splitting FunctionSignatureTransform into multiple sub-transforms.
This is something that has been talked about for some time. By splitting up function signature optimization into several smaller "transforms" that can be composed, we are able to test each transform individually as well as make it easier to add more optimizations. Hopefully, other function signature optimizations we currently perform with separate passes can be combined into this framework. NFC.
1 parent 6b2fb84 commit ee79f06

File tree

1 file changed

+138
-120
lines changed

1 file changed

+138
-120
lines changed

lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp

Lines changed: 138 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -159,17 +159,10 @@ class FunctionSignatureTransform {
159159
void OwnedToGuaranteedTransformFunctionParameters();
160160

161161
/// Find any owned to guaranteed opportunities.
162-
bool OwnedToGuaranteedAnalyze() {
163-
bool Result = OwnedToGuaranteedAnalyzeResults();
164-
bool Params = OwnedToGuaranteedAnalyzeParameters();
165-
return Params || Result;
166-
}
162+
bool OwnedToGuaranteedAnalyze();
167163

168164
/// Do the actual owned to guaranteed transformations.
169-
void OwnedToGuaranteedTransform() {
170-
OwnedToGuaranteedTransformFunctionResults();
171-
OwnedToGuaranteedTransformFunctionParameters();
172-
}
165+
void OwnedToGuaranteedTransform();
173166

174167
/// Set up epilogue work for the thunk result based in the given argument.
175168
void OwnedToGuaranteedAddResultRelease(ResultDescriptor &RD,
@@ -197,25 +190,8 @@ class FunctionSignatureTransform {
197190
/// Every transformation must defines this interface. Default implementation
198191
/// simply passes it through.
199192
void addThunkArgument(ArgumentDescriptor &AD, SILBuilder &Builder,
200-
SILBasicBlock *BB,
201-
llvm::SmallVectorImpl<SILValue> &NewArgs) {
202-
// Dead argument.
203-
if (AD.IsEntirelyDead) {
204-
return;
205-
}
206-
207-
// Explode the argument.
208-
if (AD.Explode) {
209-
llvm::SmallVector<SILValue, 4> LeafValues;
210-
AD.ProjTree.createTreeFromValue(Builder, BB->getParent()->getLocation(),
211-
BB->getArgument(AD.Index), LeafValues);
212-
NewArgs.append(LeafValues.begin(), LeafValues.end());
213-
return;
214-
}
215-
216-
// All other arguments get pushed as what they are.
217-
NewArgs.push_back(BB->getArgument(AD.Index));
218-
}
193+
SILBasicBlock *BB,
194+
llvm::SmallVectorImpl<SILValue> &NewArgs);
219195

220196
/// Take ArgumentDescList and ResultDescList and create an optimized function
221197
/// based on the current function we are analyzing. This also has the side effect
@@ -241,105 +217,35 @@ class FunctionSignatureTransform {
241217
}
242218

243219
/// Run the optimization.
244-
bool run(bool hasCaller) {
245-
bool Changed = false;
246-
SILFunction *F = TransformDescriptor.OriginalFunction;
247-
248-
if (!hasCaller && canBeCalledIndirectly(F->getRepresentation())) {
249-
DEBUG(llvm::dbgs() << " function has no caller -> abort\n");
250-
return false;
251-
}
252-
253-
// Run OwnedToGuaranteed optimization.
254-
if (OwnedToGuaranteedAnalyze()) {
255-
Changed = true;
256-
DEBUG(llvm::dbgs() << " transform owned-to-guaranteed\n");
257-
OwnedToGuaranteedTransform();
258-
}
259-
260-
// Run DeadArgument elimination transformation. We only specialize
261-
// if this function has a caller inside the current module or we have
262-
// already created a thunk.
263-
if ((hasCaller || Changed) && DeadArgumentAnalyzeParameters()) {
264-
Changed = true;
265-
DEBUG(llvm::dbgs() << " remove dead arguments\n");
266-
DeadArgumentTransformFunction();
267-
}
268-
269-
// Run ArgumentExplosion transformation. We only specialize
270-
// if this function has a caller inside the current module or we have
271-
// already created a thunk.
272-
//
273-
// NOTE: we run argument explosion last because we've already initialized
274-
// the ArgumentDescList to have unexploded number of arguments. Exploding
275-
// it without changing the argument count is not going to help with
276-
// owned-to-guaranteed transformation.
277-
//
278-
// In order to not miss any opportunity, we send the optimized function
279-
// to the passmanager to optimize any opportunities exposed by argument
280-
// explosion.
281-
if ((hasCaller || Changed) && ArgumentExplosionAnalyzeParameters()) {
282-
Changed = true;
283-
}
284-
285-
// Check if generic signature of the function could be changed by
286-
// removed some unused generic arguments.
287-
if (F->getLoweredFunctionType()->isPolymorphic() &&
288-
createOptimizedSILFunctionType() != F->getLoweredFunctionType()) {
289-
Changed = true;
290-
}
291-
292-
// Create the specialized function and invalidate the old function.
293-
if (Changed) {
294-
createFunctionSignatureOptimizedFunction();
295-
}
296-
return Changed;
297-
}
220+
bool run(bool hasCaller);
298221

299222
/// Run dead argument elimination of partially applied functions.
223+
///
300224
/// After this optimization CapturePropagation can replace the partial_apply
301225
/// by a direct reference to the specialized function.
302-
bool removeDeadArgs(int minPartialAppliedArgs) {
303-
if (minPartialAppliedArgs < 1)
304-
return false;
305-
306-
if (!DeadArgumentAnalyzeParameters())
307-
return false;
308-
309-
SILFunction *F = TransformDescriptor.OriginalFunction;
310-
auto ArgumentDescList = TransformDescriptor.ArgumentDescList;
311-
312-
// Check if at least the minimum number of partially applied arguments
313-
// are dead. Otherwise no partial_apply can be removed anyway.
314-
unsigned Size = ArgumentDescList.size();
315-
for (unsigned Idx : range(Size)) {
316-
if (Idx < Size - minPartialAppliedArgs) {
317-
// Don't remove arguments other than the partial applied ones, even if
318-
// they are dead.
319-
ArgumentDescList[Idx].IsEntirelyDead = false;
320-
continue;
321-
}
322-
323-
// Is the partially applied argument dead?
324-
if (!ArgumentDescList[Idx].IsEntirelyDead)
325-
return false;
226+
bool removeDeadArgs(int minPartialAppliedArgs);
227+
};
326228

327-
// Currently we require that all dead parameters have trivial types. The
328-
// reason is that it's very hard to find places where we can release those
329-
// parameters (as a replacement for the removed partial_apply).
330-
//
331-
// TODO: Maybe we can skip this restriction when we have semantic ARC.
332-
if (ArgumentDescList[Idx].Arg->getType().isTrivial(F->getModule()))
333-
continue;
334-
return false;
335-
}
229+
void FunctionSignatureTransform::addThunkArgument(
230+
ArgumentDescriptor &AD, SILBuilder &Builder, SILBasicBlock *BB,
231+
llvm::SmallVectorImpl<SILValue> &NewArgs) {
232+
// Dead argument.
233+
if (AD.IsEntirelyDead) {
234+
return;
235+
}
336236

337-
DEBUG(llvm::dbgs() << " remove dead arguments for partial_apply\n");
338-
DeadArgumentTransformFunction();
339-
createFunctionSignatureOptimizedFunction();
340-
return true;
237+
// Explode the argument.
238+
if (AD.Explode) {
239+
llvm::SmallVector<SILValue, 4> LeafValues;
240+
AD.ProjTree.createTreeFromValue(Builder, BB->getParent()->getLocation(),
241+
BB->getArgument(AD.Index), LeafValues);
242+
NewArgs.append(LeafValues.begin(), LeafValues.end());
243+
return;
341244
}
342-
};
245+
246+
// All other arguments get pushed as what they are.
247+
NewArgs.push_back(BB->getArgument(AD.Index));
248+
}
343249

344250
std::string FunctionSignatureTransform::createOptimizedSILFunctionName() {
345251
SILFunction *F = TransformDescriptor.OriginalFunction;
@@ -790,6 +696,107 @@ void FunctionSignatureTransform::createFunctionSignatureOptimizedFunction() {
790696
assert(F->getDebugScope()->Parent != NewF->getDebugScope()->Parent);
791697
}
792698

699+
// Run the optimization.
700+
bool FunctionSignatureTransform::run(bool hasCaller) {
701+
bool Changed = false;
702+
SILFunction *F = TransformDescriptor.OriginalFunction;
703+
704+
if (!hasCaller && canBeCalledIndirectly(F->getRepresentation())) {
705+
DEBUG(llvm::dbgs() << " function has no caller -> abort\n");
706+
return false;
707+
}
708+
709+
// Run OwnedToGuaranteed optimization.
710+
if (OwnedToGuaranteedAnalyze()) {
711+
Changed = true;
712+
DEBUG(llvm::dbgs() << " transform owned-to-guaranteed\n");
713+
OwnedToGuaranteedTransform();
714+
}
715+
716+
// Run DeadArgument elimination transformation. We only specialize
717+
// if this function has a caller inside the current module or we have
718+
// already created a thunk.
719+
if ((hasCaller || Changed) && DeadArgumentAnalyzeParameters()) {
720+
Changed = true;
721+
DEBUG(llvm::dbgs() << " remove dead arguments\n");
722+
DeadArgumentTransformFunction();
723+
}
724+
725+
// Run ArgumentExplosion transformation. We only specialize
726+
// if this function has a caller inside the current module or we have
727+
// already created a thunk.
728+
//
729+
// NOTE: we run argument explosion last because we've already initialized
730+
// the ArgumentDescList to have unexploded number of arguments. Exploding
731+
// it without changing the argument count is not going to help with
732+
// owned-to-guaranteed transformation.
733+
//
734+
// In order to not miss any opportunity, we send the optimized function
735+
// to the passmanager to optimize any opportunities exposed by argument
736+
// explosion.
737+
if ((hasCaller || Changed) && ArgumentExplosionAnalyzeParameters()) {
738+
Changed = true;
739+
}
740+
741+
// Check if generic signature of the function could be changed by
742+
// removed some unused generic arguments.
743+
if (F->getLoweredFunctionType()->isPolymorphic() &&
744+
createOptimizedSILFunctionType() != F->getLoweredFunctionType()) {
745+
Changed = true;
746+
}
747+
748+
// Create the specialized function and invalidate the old function.
749+
if (Changed) {
750+
createFunctionSignatureOptimizedFunction();
751+
}
752+
return Changed;
753+
}
754+
755+
// Run dead argument elimination of partially applied functions.
756+
//
757+
// After this optimization CapturePropagation can replace the partial_apply by a
758+
// direct reference to the specialized function.
759+
bool FunctionSignatureTransform::removeDeadArgs(int minPartialAppliedArgs) {
760+
if (minPartialAppliedArgs < 1)
761+
return false;
762+
763+
if (!DeadArgumentAnalyzeParameters())
764+
return false;
765+
766+
SILFunction *F = TransformDescriptor.OriginalFunction;
767+
auto ArgumentDescList = TransformDescriptor.ArgumentDescList;
768+
769+
// Check if at least the minimum number of partially applied arguments
770+
// are dead. Otherwise no partial_apply can be removed anyway.
771+
unsigned Size = ArgumentDescList.size();
772+
for (unsigned Idx : range(Size)) {
773+
if (Idx < Size - minPartialAppliedArgs) {
774+
// Don't remove arguments other than the partial applied ones, even if
775+
// they are dead.
776+
ArgumentDescList[Idx].IsEntirelyDead = false;
777+
continue;
778+
}
779+
780+
// Is the partially applied argument dead?
781+
if (!ArgumentDescList[Idx].IsEntirelyDead)
782+
return false;
783+
784+
// Currently we require that all dead parameters have trivial types. The
785+
// reason is that it's very hard to find places where we can release those
786+
// parameters (as a replacement for the removed partial_apply).
787+
//
788+
// TODO: Maybe we can skip this restriction when we have semantic ARC.
789+
if (ArgumentDescList[Idx].Arg->getType().isTrivial(F->getModule()))
790+
continue;
791+
return false;
792+
}
793+
794+
DEBUG(llvm::dbgs() << " remove dead arguments for partial_apply\n");
795+
DeadArgumentTransformFunction();
796+
createFunctionSignatureOptimizedFunction();
797+
return true;
798+
}
799+
793800
//===----------------------------------------------------------------------===//
794801
// Dead Argument Elimination
795802
//===----------------------------------------------------------------------===//
@@ -1076,6 +1083,17 @@ OwnedToGuaranteedAddResultRelease(ResultDescriptor &RD, SILBuilder &Builder,
10761083
}
10771084
}
10781085

1086+
bool FunctionSignatureTransform::OwnedToGuaranteedAnalyze() {
1087+
bool Result = OwnedToGuaranteedAnalyzeResults();
1088+
bool Params = OwnedToGuaranteedAnalyzeParameters();
1089+
return Params || Result;
1090+
}
1091+
1092+
void FunctionSignatureTransform::OwnedToGuaranteedTransform() {
1093+
OwnedToGuaranteedTransformFunctionResults();
1094+
OwnedToGuaranteedTransformFunctionParameters();
1095+
}
1096+
10791097
//===----------------------------------------------------------------------===//
10801098
// Argument Explosion Transformation
10811099
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)