mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
SIL optimizations: Implement the new API for analysis invalidation.
There are now separate functions for function addition and deletion instead of InvalidationKind::Function. Also, there is a new function for witness/vtable invalidations. rdar://problem/29311657
This commit is contained in:
@@ -263,15 +263,24 @@ public:
|
|||||||
/// Encodes the memory behavior query as a MemBehaviorKeyTy.
|
/// Encodes the memory behavior query as a MemBehaviorKeyTy.
|
||||||
MemBehaviorKeyTy toMemoryBehaviorKey(SILValue V1, SILValue V2, RetainObserveKind K);
|
MemBehaviorKeyTy toMemoryBehaviorKey(SILValue V1, SILValue V2, RetainObserveKind K);
|
||||||
|
|
||||||
virtual void invalidate(SILAnalysis::InvalidationKind K) override {
|
virtual void invalidate() override {
|
||||||
AliasCache.clear();
|
AliasCache.clear();
|
||||||
MemoryBehaviorCache.clear();
|
MemoryBehaviorCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void invalidate(SILFunction *,
|
virtual void invalidate(SILFunction *,
|
||||||
SILAnalysis::InvalidationKind K) override {
|
SILAnalysis::InvalidationKind K) override {
|
||||||
invalidate(K);
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Notify the analysis about a newly created function.
|
||||||
|
virtual void notifyAddFunction(SILFunction *F) override { }
|
||||||
|
|
||||||
|
/// Notify the analysis about a function which will be deleted from the
|
||||||
|
/// module.
|
||||||
|
virtual void notifyDeleteFunction(SILFunction *F) override { }
|
||||||
|
|
||||||
|
virtual void invalidateFunctionTables() override { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -55,13 +55,6 @@ namespace swift {
|
|||||||
/// has been modified.
|
/// has been modified.
|
||||||
Branches = 0x4,
|
Branches = 0x4,
|
||||||
|
|
||||||
/// The pass delete or created new functions.
|
|
||||||
///
|
|
||||||
/// The intent behind this is so that analyses that cache
|
|
||||||
/// SILFunction* to be able to be invalidated and later
|
|
||||||
/// recomputed so that they are not holding dangling pointers.
|
|
||||||
Functions = 0x8,
|
|
||||||
|
|
||||||
/// Convenience states:
|
/// Convenience states:
|
||||||
FunctionBody = Calls | Branches | Instructions,
|
FunctionBody = Calls | Branches | Instructions,
|
||||||
|
|
||||||
@@ -69,7 +62,7 @@ namespace swift {
|
|||||||
|
|
||||||
BranchesAndInstructions = Branches | Instructions,
|
BranchesAndInstructions = Branches | Instructions,
|
||||||
|
|
||||||
Everything = Functions | Calls | Branches | Instructions,
|
Everything = Calls | Branches | Instructions,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A list of the known analysis.
|
/// A list of the known analysis.
|
||||||
@@ -112,22 +105,20 @@ namespace swift {
|
|||||||
bool isLocked() { return invalidationLock; }
|
bool isLocked() { return invalidationLock; }
|
||||||
|
|
||||||
/// Invalidate all information in this analysis.
|
/// Invalidate all information in this analysis.
|
||||||
virtual void invalidate(InvalidationKind K) {}
|
virtual void invalidate() = 0;
|
||||||
|
|
||||||
/// Invalidate all of the information for a specific function.
|
/// Invalidate all of the information for a specific function.
|
||||||
virtual void invalidate(SILFunction *F, InvalidationKind K) {}
|
virtual void invalidate(SILFunction *F, InvalidationKind K) = 0;
|
||||||
|
|
||||||
/// Invalidate all of the information for a specific function. Also, we
|
|
||||||
/// know that this function is a dead function and going to be deleted from
|
|
||||||
/// the module.
|
|
||||||
virtual void invalidateForDeadFunction(SILFunction *F, InvalidationKind K) {
|
|
||||||
// Call the normal invalidate function unless overridden by specific
|
|
||||||
// analysis.
|
|
||||||
invalidate(F, K);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Notify the analysis about a newly created function.
|
/// Notify the analysis about a newly created function.
|
||||||
virtual void notifyAnalysisOfFunction(SILFunction *F) {}
|
virtual void notifyAddFunction(SILFunction *F) = 0;
|
||||||
|
|
||||||
|
/// Notify the analysis about a function which will be deleted from the
|
||||||
|
/// module.
|
||||||
|
virtual void notifyDeleteFunction(SILFunction *F) = 0;
|
||||||
|
|
||||||
|
/// Notify the analysis about changed witness or vtables.
|
||||||
|
virtual void invalidateFunctionTables() = 0;
|
||||||
|
|
||||||
/// Verify the state of this analysis.
|
/// Verify the state of this analysis.
|
||||||
virtual void verify() const {}
|
virtual void verify() const {}
|
||||||
@@ -190,19 +181,13 @@ namespace swift {
|
|||||||
return it.second;
|
return it.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void invalidate(SILAnalysis::InvalidationKind K) override {
|
/// Invalidate all information in this analysis.
|
||||||
if (!shouldInvalidate(K)) return;
|
virtual void invalidate() override {
|
||||||
|
|
||||||
for (auto D : Storage)
|
|
||||||
delete D.second;
|
|
||||||
|
|
||||||
Storage.clear();
|
Storage.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void invalidate(SILFunction *F,
|
/// Helper function to remove the analysis data for a function.
|
||||||
SILAnalysis::InvalidationKind K) override {
|
void invalidateFunction(SILFunction *F) {
|
||||||
if (!shouldInvalidate(K)) return;
|
|
||||||
|
|
||||||
auto &it = Storage.FindAndConstruct(F);
|
auto &it = Storage.FindAndConstruct(F);
|
||||||
if (it.second) {
|
if (it.second) {
|
||||||
delete it.second;
|
delete it.second;
|
||||||
@@ -210,6 +195,25 @@ namespace swift {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Invalidate all of the information for a specific function.
|
||||||
|
virtual void invalidate(SILFunction *F,
|
||||||
|
SILAnalysis::InvalidationKind K) override {
|
||||||
|
if (shouldInvalidate(K))
|
||||||
|
invalidateFunction(F);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Notify the analysis about a newly created function.
|
||||||
|
virtual void notifyAddFunction(SILFunction *F) override { }
|
||||||
|
|
||||||
|
/// Notify the analysis about a function which will be deleted from the
|
||||||
|
/// module.
|
||||||
|
virtual void notifyDeleteFunction(SILFunction *F) override {
|
||||||
|
invalidateFunction(F);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Notify the analysis about changed witness or vtables.
|
||||||
|
virtual void invalidateFunctionTables() override { }
|
||||||
|
|
||||||
FunctionAnalysisBase() {}
|
FunctionAnalysisBase() {}
|
||||||
virtual ~FunctionAnalysisBase() {
|
virtual ~FunctionAnalysisBase() {
|
||||||
for (auto D : Storage)
|
for (auto D : Storage)
|
||||||
|
|||||||
@@ -132,12 +132,25 @@ public:
|
|||||||
return S->getKind() == AnalysisKind::BasicCallee;
|
return S->getKind() == AnalysisKind::BasicCallee;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void invalidate(SILAnalysis::InvalidationKind K) {
|
/// Invalidate all information in this analysis.
|
||||||
if (K & InvalidationKind::Functions)
|
virtual void invalidate() override {
|
||||||
Cache.reset();
|
Cache.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void invalidate(SILFunction *F, InvalidationKind K) { invalidate(K); }
|
/// Invalidate all of the information for a specific function.
|
||||||
|
virtual void invalidate(SILFunction *F, InvalidationKind K) override { }
|
||||||
|
|
||||||
|
/// Notify the analysis about a newly created function.
|
||||||
|
virtual void notifyAddFunction(SILFunction *F) override { }
|
||||||
|
|
||||||
|
/// Notify the analysis about a function which will be deleted from the
|
||||||
|
/// module.
|
||||||
|
virtual void notifyDeleteFunction(SILFunction *F) override { };
|
||||||
|
|
||||||
|
/// Notify the analysis about changed witness or vtables.
|
||||||
|
virtual void invalidateFunctionTables() override {
|
||||||
|
Cache.reset();
|
||||||
|
}
|
||||||
|
|
||||||
CalleeList getCalleeList(FullApplySite FAS) {
|
CalleeList getCalleeList(FullApplySite FAS) {
|
||||||
if (!Cache)
|
if (!Cache)
|
||||||
|
|||||||
@@ -121,11 +121,17 @@ public:
|
|||||||
return S->getKind() == AnalysisKind::Caller;
|
return S->getKind() == AnalysisKind::Caller;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void notifyAnalysisOfFunction(SILFunction *F) {
|
/// Invalidate all information in this analysis.
|
||||||
RecomputeFunctionList.insert(F);
|
virtual void invalidate() override {
|
||||||
|
FuncInfos.clear();
|
||||||
|
RecomputeFunctionList.clear();
|
||||||
|
for (auto &F : Mod) {
|
||||||
|
RecomputeFunctionList.insert(&F);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void invalidate(SILFunction *F, InvalidationKind K) {
|
/// Invalidate all of the information for a specific function.
|
||||||
|
virtual void invalidate(SILFunction *F, InvalidationKind K) override {
|
||||||
// Should we invalidate based on the invalidation kind.
|
// Should we invalidate based on the invalidation kind.
|
||||||
bool shouldInvalidate = K & InvalidationKind::CallsAndInstructions;
|
bool shouldInvalidate = K & InvalidationKind::CallsAndInstructions;
|
||||||
if (!shouldInvalidate)
|
if (!shouldInvalidate)
|
||||||
@@ -138,23 +144,20 @@ public:
|
|||||||
RecomputeFunctionList.insert(F);
|
RecomputeFunctionList.insert(F);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void invalidateForDeadFunction(SILFunction *F, InvalidationKind K) {
|
/// Notify the analysis about a newly created function.
|
||||||
|
virtual void notifyAddFunction(SILFunction *F) override {
|
||||||
|
RecomputeFunctionList.insert(F);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Notify the analysis about a function which will be deleted from the
|
||||||
|
/// module.
|
||||||
|
virtual void notifyDeleteFunction(SILFunction *F) override {
|
||||||
invalidateExistingCalleeRelation(F);
|
invalidateExistingCalleeRelation(F);
|
||||||
RecomputeFunctionList.remove(F);
|
RecomputeFunctionList.remove(F);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void invalidate(InvalidationKind K) {
|
/// Notify the analysis about changed witness or vtables.
|
||||||
// Should we invalidate based on the invalidation kind.
|
virtual void invalidateFunctionTables() override { }
|
||||||
bool shouldInvalidate = K & InvalidationKind::Calls;
|
|
||||||
if (!shouldInvalidate)
|
|
||||||
return;
|
|
||||||
|
|
||||||
FuncInfos.clear();
|
|
||||||
RecomputeFunctionList.clear();
|
|
||||||
for (auto &F : Mod) {
|
|
||||||
RecomputeFunctionList.insert(&F);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const FunctionInfo &getCallerInfo(SILFunction *F) {
|
const FunctionInfo &getCallerInfo(SILFunction *F) {
|
||||||
// Recompute every function in the invalidated function list and empty the
|
// Recompute every function in the invalidated function list and empty the
|
||||||
|
|||||||
@@ -44,10 +44,24 @@ public:
|
|||||||
return S->getKind() == AnalysisKind::ClassHierarchy;
|
return S->getKind() == AnalysisKind::ClassHierarchy;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void invalidate(SILAnalysis::InvalidationKind K) {
|
/// Invalidate all information in this analysis.
|
||||||
// Nothing can invalidate the ClassHierarchyAnalysis!
|
virtual void invalidate() override {
|
||||||
|
// Nothing can invalidate, because types are static and cannot be changed
|
||||||
|
// during the SIL pass pipeline.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Invalidate all of the information for a specific function.
|
||||||
|
virtual void invalidate(SILFunction *F, InvalidationKind K) override { }
|
||||||
|
|
||||||
|
/// Notify the analysis about a newly created function.
|
||||||
|
virtual void notifyAddFunction(SILFunction *F) override { }
|
||||||
|
|
||||||
|
/// Notify the analysis about a function which will be deleted from the
|
||||||
|
/// module.
|
||||||
|
virtual void notifyDeleteFunction(SILFunction *F) override { }
|
||||||
|
|
||||||
|
/// Notify the analysis about changed witness or vtables.
|
||||||
|
virtual void invalidateFunctionTables() override { }
|
||||||
|
|
||||||
/// Returns a list of the known direct subclasses of a class \p C in
|
/// Returns a list of the known direct subclasses of a class \p C in
|
||||||
/// the current module.
|
/// the current module.
|
||||||
@@ -87,10 +101,6 @@ public:
|
|||||||
return ProtocolImplementationsCache.count(C);
|
return ProtocolImplementationsCache.count(C);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void invalidate(SILFunction *F, SILAnalysis::InvalidationKind K) {
|
|
||||||
invalidate(K);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Compute inheritance properties.
|
/// Compute inheritance properties.
|
||||||
void init();
|
void init();
|
||||||
|
|||||||
@@ -34,6 +34,22 @@ public:
|
|||||||
/// Returns true if destruction of T may store to memory.
|
/// Returns true if destruction of T may store to memory.
|
||||||
bool mayStoreToMemoryOnDestruction(SILType T);
|
bool mayStoreToMemoryOnDestruction(SILType T);
|
||||||
|
|
||||||
|
/// No invalidation is needed.
|
||||||
|
virtual void invalidate() override { }
|
||||||
|
|
||||||
|
/// No invalidation is needed.
|
||||||
|
virtual void invalidate(SILFunction *F, InvalidationKind K) override { }
|
||||||
|
|
||||||
|
/// Notify the analysis about a newly created function.
|
||||||
|
virtual void notifyAddFunction(SILFunction *F) override { }
|
||||||
|
|
||||||
|
/// Notify the analysis about a function which will be deleted from the
|
||||||
|
/// module.
|
||||||
|
virtual void notifyDeleteFunction(SILFunction *F) override { }
|
||||||
|
|
||||||
|
/// Notify the analysis about changed witness or vtables.
|
||||||
|
virtual void invalidateFunctionTables() override { }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool cacheResult(CanType Type, bool Result);
|
bool cacheResult(CanType Type, bool Result);
|
||||||
bool isSafeType(CanType Ty);
|
bool isSafeType(CanType Ty);
|
||||||
|
|||||||
@@ -791,10 +791,24 @@ public:
|
|||||||
/// node, the pointers do not alias.
|
/// node, the pointers do not alias.
|
||||||
bool canPointToSameMemory(SILValue V1, SILValue V2);
|
bool canPointToSameMemory(SILValue V1, SILValue V2);
|
||||||
|
|
||||||
virtual void invalidate(InvalidationKind K) override;
|
/// Invalidate all information in this analysis.
|
||||||
|
virtual void invalidate() override;
|
||||||
|
|
||||||
|
/// Invalidate all of the information for a specific function.
|
||||||
virtual void invalidate(SILFunction *F, InvalidationKind K) override;
|
virtual void invalidate(SILFunction *F, InvalidationKind K) override;
|
||||||
|
|
||||||
|
/// Notify the analysis about a newly created function.
|
||||||
|
virtual void notifyAddFunction(SILFunction *F) override { }
|
||||||
|
|
||||||
|
/// Notify the analysis about a function which will be deleted from the
|
||||||
|
/// module.
|
||||||
|
virtual void notifyDeleteFunction(SILFunction *F) override {
|
||||||
|
invalidate(F, InvalidationKind::Nothing);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Notify the analysis about changed witness or vtables.
|
||||||
|
virtual void invalidateFunctionTables() override { }
|
||||||
|
|
||||||
virtual void handleDeleteNotification(ValueBase *I) override;
|
virtual void handleDeleteNotification(ValueBase *I) override;
|
||||||
|
|
||||||
virtual bool needsNotifications() override { return true; }
|
virtual bool needsNotifications() override { return true; }
|
||||||
|
|||||||
@@ -379,11 +379,23 @@ public:
|
|||||||
/// Get the side-effects of a call site.
|
/// Get the side-effects of a call site.
|
||||||
void getEffects(FunctionEffects &ApplyEffects, FullApplySite FAS);
|
void getEffects(FunctionEffects &ApplyEffects, FullApplySite FAS);
|
||||||
|
|
||||||
/// No invalidation is needed. See comment for SideEffectAnalysis.
|
/// Invalidate all information in this analysis.
|
||||||
virtual void invalidate(InvalidationKind K) override;
|
virtual void invalidate() override;
|
||||||
|
|
||||||
/// No invalidation is needed. See comment for SideEffectAnalysis.
|
/// Invalidate all of the information for a specific function.
|
||||||
virtual void invalidate(SILFunction *F, InvalidationKind K) override;
|
virtual void invalidate(SILFunction *F, InvalidationKind K) override;
|
||||||
|
|
||||||
|
/// Notify the analysis about a newly created function.
|
||||||
|
virtual void notifyAddFunction(SILFunction *F) override { }
|
||||||
|
|
||||||
|
/// Notify the analysis about a function which will be deleted from the
|
||||||
|
/// module.
|
||||||
|
virtual void notifyDeleteFunction(SILFunction *F) override {
|
||||||
|
invalidate(F, InvalidationKind::Nothing);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Notify the analysis about changed witness or vtables.
|
||||||
|
virtual void invalidateFunctionTables() override { }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace swift
|
} // end namespace swift
|
||||||
|
|||||||
@@ -33,6 +33,25 @@ public:
|
|||||||
|
|
||||||
/// Return ProjectionPath to every leaf or intermediate node of the given type.
|
/// Return ProjectionPath to every leaf or intermediate node of the given type.
|
||||||
const ProjectionPathList &getTypeExpansion(SILType B, SILModule *Mod);
|
const ProjectionPathList &getTypeExpansion(SILType B, SILModule *Mod);
|
||||||
|
|
||||||
|
/// Invalidate all information in this analysis.
|
||||||
|
virtual void invalidate() override {
|
||||||
|
// Nothing can invalidate, because types are static and cannot be changed
|
||||||
|
// during the SIL pass pipeline.
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invalidate all of the information for a specific function.
|
||||||
|
virtual void invalidate(SILFunction *F, InvalidationKind K) override { }
|
||||||
|
|
||||||
|
/// Notify the analysis about a newly created function.
|
||||||
|
virtual void notifyAddFunction(SILFunction *F) override { }
|
||||||
|
|
||||||
|
/// Notify the analysis about a function which will be deleted from the
|
||||||
|
/// module.
|
||||||
|
virtual void notifyDeleteFunction(SILFunction *F) override { }
|
||||||
|
|
||||||
|
/// Notify the analysis about changed witness or vtables.
|
||||||
|
virtual void invalidateFunctionTables() override { }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,14 +140,12 @@ public:
|
|||||||
void clearRestartPipeline() { RestartPipeline = false; }
|
void clearRestartPipeline() { RestartPipeline = false; }
|
||||||
bool shouldRestartPipeline() { return RestartPipeline; }
|
bool shouldRestartPipeline() { return RestartPipeline; }
|
||||||
|
|
||||||
/// \brief Broadcast the invalidation of the module to all analysis.
|
/// \brief Iterate over all analysis and invalidate them.
|
||||||
void invalidateAnalysis(SILAnalysis::InvalidationKind K) {
|
void invalidateAllAnalysis() {
|
||||||
assert(K != SILAnalysis::InvalidationKind::Nothing &&
|
// Invalidate the analysis (unless they are locked)
|
||||||
"Invalidation call must invalidate some trait");
|
|
||||||
|
|
||||||
for (auto AP : Analysis)
|
for (auto AP : Analysis)
|
||||||
if (!AP->isLocked())
|
if (!AP->isLocked())
|
||||||
AP->invalidate(K);
|
AP->invalidate();
|
||||||
|
|
||||||
CurrentPassHasInvalidated = true;
|
CurrentPassHasInvalidated = true;
|
||||||
|
|
||||||
@@ -167,7 +165,7 @@ public:
|
|||||||
/// particular analysis has been done on the function.
|
/// particular analysis has been done on the function.
|
||||||
void notifyAnalysisOfFunction(SILFunction *F) {
|
void notifyAnalysisOfFunction(SILFunction *F) {
|
||||||
for (auto AP : Analysis)
|
for (auto AP : Analysis)
|
||||||
AP->notifyAnalysisOfFunction(F);
|
AP->notifyAddFunction(F);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Broadcast the invalidation of the function to all analysis.
|
/// \brief Broadcast the invalidation of the function to all analysis.
|
||||||
@@ -183,15 +181,26 @@ public:
|
|||||||
CompletedPassesMap[F].reset();
|
CompletedPassesMap[F].reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Broadcast the invalidation of the function to all analysis.
|
/// \brief Iterate over all analysis and notify them of a change in witness-
|
||||||
/// And we also know this function is dead and will be removed from the
|
/// or vtables.
|
||||||
/// module.
|
void invalidateFunctionTables() {
|
||||||
void invalidateAnalysisForDeadFunction(SILFunction *F,
|
|
||||||
SILAnalysis::InvalidationKind K) {
|
|
||||||
// Invalidate the analysis (unless they are locked)
|
// Invalidate the analysis (unless they are locked)
|
||||||
for (auto AP : Analysis)
|
for (auto AP : Analysis)
|
||||||
if (!AP->isLocked())
|
if (!AP->isLocked())
|
||||||
AP->invalidateForDeadFunction(F, K);
|
AP->invalidateFunctionTables();
|
||||||
|
|
||||||
|
CurrentPassHasInvalidated = true;
|
||||||
|
|
||||||
|
// Assume that all functions have changed. Clear all masks of all functions.
|
||||||
|
CompletedPassesMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Iterate over all analysis and notify them of a deleted function.
|
||||||
|
void notifyDeleteFunction(SILFunction *F) {
|
||||||
|
// Invalidate the analysis (unless they are locked)
|
||||||
|
for (auto AP : Analysis)
|
||||||
|
if (!AP->isLocked())
|
||||||
|
AP->notifyDeleteFunction(F);
|
||||||
|
|
||||||
CurrentPassHasInvalidated = true;
|
CurrentPassHasInvalidated = true;
|
||||||
// Any change let all passes run again.
|
// Any change let all passes run again.
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
namespace swift {
|
namespace swift {
|
||||||
class SILOptions;
|
class SILOptions;
|
||||||
class SILTransform;
|
class SILTransform;
|
||||||
|
class SILModuleTransform;
|
||||||
|
|
||||||
namespace irgen {
|
namespace irgen {
|
||||||
class IRGenModule;
|
class IRGenModule;
|
||||||
@@ -46,7 +47,7 @@ namespace swift {
|
|||||||
|
|
||||||
/// \brief Detect and remove unreachable code. Diagnose provably unreachable
|
/// \brief Detect and remove unreachable code. Diagnose provably unreachable
|
||||||
/// user code.
|
/// user code.
|
||||||
void performSILDiagnoseUnreachable(SILModule *M);
|
void performSILDiagnoseUnreachable(SILModule *M, SILModuleTransform *T);
|
||||||
|
|
||||||
/// \brief Remove dead functions from \p M.
|
/// \brief Remove dead functions from \p M.
|
||||||
void performSILDeadFunctionElimination(SILModule *M);
|
void performSILDeadFunctionElimination(SILModule *M);
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ namespace swift {
|
|||||||
/// derived from a common base function, e.g. due to specialization.
|
/// derived from a common base function, e.g. due to specialization.
|
||||||
/// The number should be small anyway, but bugs in optimizations could cause
|
/// The number should be small anyway, but bugs in optimizations could cause
|
||||||
/// an infinite loop in the passmanager.
|
/// an infinite loop in the passmanager.
|
||||||
void notifyPassManagerOfFunction(SILFunction *F, SILFunction *DerivedFrom) {
|
void notifyAddFunction(SILFunction *F, SILFunction *DerivedFrom) {
|
||||||
PM->addFunctionToWorklist(F, DerivedFrom);
|
PM->addFunctionToWorklist(F, DerivedFrom);
|
||||||
PM->notifyAnalysisOfFunction(F);
|
PM->notifyAnalysisOfFunction(F);
|
||||||
}
|
}
|
||||||
@@ -146,10 +146,9 @@ namespace swift {
|
|||||||
|
|
||||||
SILModule *getModule() { return M; }
|
SILModule *getModule() { return M; }
|
||||||
|
|
||||||
/// Invalidate all of functions in the module, using invalidation
|
/// Invalidate all analsysis data for the whole module.
|
||||||
/// information \p K.
|
void invalidateAll() {
|
||||||
void invalidateAnalysis(SILAnalysis::InvalidationKind K) {
|
PM->invalidateAllAnalysis();
|
||||||
PM->invalidateAnalysis(K);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invalidate only the function \p F, using invalidation information \p K.
|
/// Invalidate only the function \p F, using invalidation information \p K.
|
||||||
@@ -157,11 +156,19 @@ namespace swift {
|
|||||||
PM->invalidateAnalysis(F, K);
|
PM->invalidateAnalysis(F, K);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invalidate only the function \p F, using invalidation information \p K.
|
/// Invalidate the analysis data for witness- and vtables.
|
||||||
/// But we also know this function is going to be dead.
|
void invalidateFunctionTables() {
|
||||||
void invalidateAnalysisForDeadFunction(SILFunction *F,
|
PM->invalidateFunctionTables();
|
||||||
SILAnalysis::InvalidationKind K) {
|
}
|
||||||
PM->invalidateAnalysisForDeadFunction(F, K);
|
|
||||||
|
/// Inform the pass manager of a deleted function.
|
||||||
|
void notifyDeleteFunction(SILFunction *F) {
|
||||||
|
PM->notifyDeleteFunction(F);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inform the pass manager of an added function.
|
||||||
|
void notifyAddFunction(SILFunction *F) {
|
||||||
|
PM->notifyAnalysisOfFunction(F);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // end namespace swift
|
} // end namespace swift
|
||||||
|
|||||||
@@ -1953,7 +1953,7 @@ bool EscapeAnalysis::canParameterEscape(FullApplySite FAS, int ParamIdx,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EscapeAnalysis::invalidate(InvalidationKind K) {
|
void EscapeAnalysis::invalidate() {
|
||||||
Function2Info.clear();
|
Function2Info.clear();
|
||||||
Allocator.DestroyAll();
|
Allocator.DestroyAll();
|
||||||
DEBUG(llvm::dbgs() << "invalidate all\n");
|
DEBUG(llvm::dbgs() << "invalidate all\n");
|
||||||
|
|||||||
@@ -515,7 +515,7 @@ void SideEffectAnalysis::getEffects(FunctionEffects &ApplyEffects, FullApplySite
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SideEffectAnalysis::invalidate(InvalidationKind K) {
|
void SideEffectAnalysis::invalidate() {
|
||||||
Function2Info.clear();
|
Function2Info.clear();
|
||||||
Allocator.DestroyAll();
|
Allocator.DestroyAll();
|
||||||
DEBUG(llvm::dbgs() << "invalidate all\n");
|
DEBUG(llvm::dbgs() << "invalidate all\n");
|
||||||
|
|||||||
@@ -851,7 +851,7 @@ constructClonedFunction(PartialApplyInst *PAI, FunctionRefInst *FRI,
|
|||||||
/// with a partial_apply of the new closure, fixing up reference counting as
|
/// with a partial_apply of the new closure, fixing up reference counting as
|
||||||
/// necessary. Also, if the closure is cloned, the cloned function is added to
|
/// necessary. Also, if the closure is cloned, the cloned function is added to
|
||||||
/// the worklist.
|
/// the worklist.
|
||||||
static void
|
static SILFunction *
|
||||||
processPartialApplyInst(PartialApplyInst *PAI, IndicesSet &PromotableIndices,
|
processPartialApplyInst(PartialApplyInst *PAI, IndicesSet &PromotableIndices,
|
||||||
SmallVectorImpl<SILFunction*> &Worklist) {
|
SmallVectorImpl<SILFunction*> &Worklist) {
|
||||||
SILModule &M = PAI->getModule();
|
SILModule &M = PAI->getModule();
|
||||||
@@ -934,6 +934,7 @@ processPartialApplyInst(PartialApplyInst *PAI, IndicesSet &PromotableIndices,
|
|||||||
// TODO: If this is the last use of the closure, and if it has internal
|
// TODO: If this is the last use of the closure, and if it has internal
|
||||||
// linkage, we should remove it from the SILModule now.
|
// linkage, we should remove it from the SILModule now.
|
||||||
}
|
}
|
||||||
|
return ClonedFn;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -961,19 +962,6 @@ constructMapFromPartialApplyToPromotableIndices(SILFunction *F,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
processFunction(SILFunction *F, SmallVectorImpl<SILFunction*> &Worklist) {
|
|
||||||
// This is a map from each partial apply to a set of indices of promotable
|
|
||||||
// box variables.
|
|
||||||
PartialApplyIndicesMap IndicesMap;
|
|
||||||
constructMapFromPartialApplyToPromotableIndices(F, IndicesMap);
|
|
||||||
|
|
||||||
// Do the actual promotions; all promotions on a single partial_apply are
|
|
||||||
// handled together.
|
|
||||||
for (auto &IndicesPair : IndicesMap)
|
|
||||||
processPartialApplyInst(IndicesPair.first, IndicesPair.second, Worklist);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class CapturePromotionPass : public SILModuleTransform {
|
class CapturePromotionPass : public SILModuleTransform {
|
||||||
/// The entry point to the transformation.
|
/// The entry point to the transformation.
|
||||||
@@ -983,17 +971,35 @@ class CapturePromotionPass : public SILModuleTransform {
|
|||||||
processFunction(&F, Worklist);
|
processFunction(&F, Worklist);
|
||||||
|
|
||||||
if (!Worklist.empty()) {
|
if (!Worklist.empty()) {
|
||||||
invalidateAnalysis(SILAnalysis::InvalidationKind::Everything);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!Worklist.empty())
|
while (!Worklist.empty())
|
||||||
processFunction(Worklist.pop_back_val(), Worklist);
|
processFunction(Worklist.pop_back_val(), Worklist);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void processFunction(SILFunction *F, SmallVectorImpl<SILFunction*> &Worklist);
|
||||||
|
|
||||||
StringRef getName() override { return "Capture Promotion"; }
|
StringRef getName() override { return "Capture Promotion"; }
|
||||||
};
|
};
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
void CapturePromotionPass::processFunction(SILFunction *F,
|
||||||
|
SmallVectorImpl<SILFunction*> &Worklist) {
|
||||||
|
// This is a map from each partial apply to a set of indices of promotable
|
||||||
|
// box variables.
|
||||||
|
PartialApplyIndicesMap IndicesMap;
|
||||||
|
constructMapFromPartialApplyToPromotableIndices(F, IndicesMap);
|
||||||
|
|
||||||
|
// Do the actual promotions; all promotions on a single partial_apply are
|
||||||
|
// handled together.
|
||||||
|
for (auto &IndicesPair : IndicesMap) {
|
||||||
|
PartialApplyInst *PAI = IndicesPair.first;
|
||||||
|
SILFunction *ClonedFn = processPartialApplyInst(PAI, IndicesPair.second,
|
||||||
|
Worklist);
|
||||||
|
notifyAddFunction(ClonedFn);
|
||||||
|
}
|
||||||
|
invalidateAnalysis(F, SILAnalysis::InvalidationKind::Everything);
|
||||||
|
}
|
||||||
|
|
||||||
SILTransform *swift::createCapturePromotion() {
|
SILTransform *swift::createCapturePromotion() {
|
||||||
return new CapturePromotionPass();
|
return new CapturePromotionPass();
|
||||||
|
|||||||
@@ -416,7 +416,7 @@ bool CapturePropagation::optimizePartialApply(PartialApplyInst *PAI) {
|
|||||||
SILFunction *NewF = specializeConstClosure(PAI, SubstF);
|
SILFunction *NewF = specializeConstClosure(PAI, SubstF);
|
||||||
rewritePartialApply(PAI, NewF);
|
rewritePartialApply(PAI, NewF);
|
||||||
|
|
||||||
notifyPassManagerOfFunction(NewF, SubstF);
|
notifyAddFunction(NewF, SubstF);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -885,7 +885,7 @@ bool SILClosureSpecializerTransform::specialize(SILFunction *Caller,
|
|||||||
// directly.
|
// directly.
|
||||||
if (!NewF) {
|
if (!NewF) {
|
||||||
NewF = ClosureSpecCloner::cloneFunction(CSDesc, NewFName);
|
NewF = ClosureSpecCloner::cloneFunction(CSDesc, NewFName);
|
||||||
notifyPassManagerOfFunction(NewF, CSDesc.getApplyCallee());
|
notifyAddFunction(NewF, CSDesc.getApplyCallee());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite the call
|
// Rewrite the call
|
||||||
|
|||||||
@@ -590,12 +590,15 @@ class DeadFunctionElimination : FunctionLivenessComputation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Removes all dead methods from vtables and witness tables.
|
/// Removes all dead methods from vtables and witness tables.
|
||||||
void removeDeadEntriesFromTables() {
|
bool removeDeadEntriesFromTables() {
|
||||||
|
bool changedTable = false;
|
||||||
for (SILVTable &vTable : Module->getVTableList()) {
|
for (SILVTable &vTable : Module->getVTableList()) {
|
||||||
vTable.removeEntries_if([this](SILVTable::Entry &entry) -> bool {
|
vTable.removeEntries_if([this, &changedTable]
|
||||||
|
(SILVTable::Entry &entry) -> bool {
|
||||||
if (!isAlive(entry.Implementation)) {
|
if (!isAlive(entry.Implementation)) {
|
||||||
DEBUG(llvm::dbgs() << " erase dead vtable method " <<
|
DEBUG(llvm::dbgs() << " erase dead vtable method " <<
|
||||||
entry.Implementation->getName() << "\n");
|
entry.Implementation->getName() << "\n");
|
||||||
|
changedTable = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -606,10 +609,12 @@ class DeadFunctionElimination : FunctionLivenessComputation {
|
|||||||
for (auto WI = WitnessTables.begin(), EI = WitnessTables.end(); WI != EI;) {
|
for (auto WI = WitnessTables.begin(), EI = WitnessTables.end(); WI != EI;) {
|
||||||
SILWitnessTable *WT = &*WI;
|
SILWitnessTable *WT = &*WI;
|
||||||
WI++;
|
WI++;
|
||||||
WT->clearMethods_if([this](const SILWitnessTable::MethodWitness &MW) -> bool {
|
WT->clearMethods_if([this, &changedTable]
|
||||||
|
(const SILWitnessTable::MethodWitness &MW) -> bool {
|
||||||
if (!isAlive(MW.Witness)) {
|
if (!isAlive(MW.Witness)) {
|
||||||
DEBUG(llvm::dbgs() << " erase dead witness method " <<
|
DEBUG(llvm::dbgs() << " erase dead witness method " <<
|
||||||
MW.Witness->getName() << "\n");
|
MW.Witness->getName() << "\n");
|
||||||
|
changedTable = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -622,17 +627,19 @@ class DeadFunctionElimination : FunctionLivenessComputation {
|
|||||||
WI != EI;) {
|
WI != EI;) {
|
||||||
SILDefaultWitnessTable *WT = &*WI;
|
SILDefaultWitnessTable *WT = &*WI;
|
||||||
WI++;
|
WI++;
|
||||||
WT->clearMethods_if([this](SILFunction *MW) -> bool {
|
WT->clearMethods_if([this, &changedTable](SILFunction *MW) -> bool {
|
||||||
if (!MW)
|
if (!MW)
|
||||||
return false;
|
return false;
|
||||||
if (!isAlive(MW)) {
|
if (!isAlive(MW)) {
|
||||||
DEBUG(llvm::dbgs() << " erase dead default witness method "
|
DEBUG(llvm::dbgs() << " erase dead default witness method "
|
||||||
<< MW->getName() << "\n");
|
<< MW->getName() << "\n");
|
||||||
|
changedTable = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
return changedTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -645,7 +652,7 @@ public:
|
|||||||
DEBUG(llvm::dbgs() << "running dead function elimination\n");
|
DEBUG(llvm::dbgs() << "running dead function elimination\n");
|
||||||
findAliveFunctions();
|
findAliveFunctions();
|
||||||
|
|
||||||
removeDeadEntriesFromTables();
|
bool changedTables = removeDeadEntriesFromTables();
|
||||||
|
|
||||||
// First drop all references so that we don't get problems with non-zero
|
// First drop all references so that we don't get problems with non-zero
|
||||||
// reference counts of dead functions.
|
// reference counts of dead functions.
|
||||||
@@ -670,16 +677,17 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Last step: delete all dead functions.
|
// Last step: delete all dead functions.
|
||||||
auto InvalidateEverything = SILAnalysis::InvalidationKind::Everything;
|
|
||||||
while (!DeadFunctions.empty()) {
|
while (!DeadFunctions.empty()) {
|
||||||
SILFunction *F = DeadFunctions.back();
|
SILFunction *F = DeadFunctions.back();
|
||||||
DeadFunctions.pop_back();
|
DeadFunctions.pop_back();
|
||||||
|
|
||||||
DEBUG(llvm::dbgs() << " erase dead function " << F->getName() << "\n");
|
DEBUG(llvm::dbgs() << " erase dead function " << F->getName() << "\n");
|
||||||
NumDeadFunc++;
|
NumDeadFunc++;
|
||||||
DFEPass->invalidateAnalysisForDeadFunction(F, InvalidateEverything);
|
DFEPass->notifyDeleteFunction(F);
|
||||||
Module->eraseFunction(F);
|
Module->eraseFunction(F);
|
||||||
}
|
}
|
||||||
|
if (changedTables)
|
||||||
|
DFEPass->invalidateFunctionTables();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -839,8 +847,7 @@ public:
|
|||||||
// Do not remove bodies of any functions that are alive.
|
// Do not remove bodies of any functions that are alive.
|
||||||
if (!isAlive(F)) {
|
if (!isAlive(F)) {
|
||||||
if (tryToConvertExternalDefinitionIntoDeclaration(F)) {
|
if (tryToConvertExternalDefinitionIntoDeclaration(F)) {
|
||||||
DFEPass->invalidateAnalysisForDeadFunction(F,
|
DFEPass->notifyDeleteFunction(F);
|
||||||
SILAnalysis::InvalidationKind::Everything);
|
|
||||||
if (F->getRefCount() == 0)
|
if (F->getRefCount() == 0)
|
||||||
F->getModule().eraseFunction(F);
|
F->getModule().eraseFunction(F);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -719,7 +719,6 @@ void EagerSpecializerTransform::run() {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Process functions in any order.
|
// Process functions in any order.
|
||||||
bool Changed = false;
|
|
||||||
for (auto &F : *getModule()) {
|
for (auto &F : *getModule()) {
|
||||||
if (!F.shouldOptimize()) {
|
if (!F.shouldOptimize()) {
|
||||||
DEBUG(dbgs() << " Cannot specialize function " << F.getName()
|
DEBUG(dbgs() << " Cannot specialize function " << F.getName()
|
||||||
@@ -744,6 +743,7 @@ void EagerSpecializerTransform::run() {
|
|||||||
auto AttrRequirements = SA->getRequirements();
|
auto AttrRequirements = SA->getRequirements();
|
||||||
ReInfoVec.emplace_back(&F, AttrRequirements);
|
ReInfoVec.emplace_back(&F, AttrRequirements);
|
||||||
auto *NewFunc = eagerSpecialize(&F, *SA, ReInfoVec.back());
|
auto *NewFunc = eagerSpecialize(&F, *SA, ReInfoVec.back());
|
||||||
|
notifyAddFunction(NewFunc);
|
||||||
|
|
||||||
SpecializedFuncs.push_back(NewFunc);
|
SpecializedFuncs.push_back(NewFunc);
|
||||||
|
|
||||||
@@ -755,6 +755,7 @@ void EagerSpecializerTransform::run() {
|
|||||||
|
|
||||||
// TODO: Optimize the dispatch code to minimize the amount
|
// TODO: Optimize the dispatch code to minimize the amount
|
||||||
// of checks. Use decision trees for this purpose.
|
// of checks. Use decision trees for this purpose.
|
||||||
|
bool Changed = false;
|
||||||
for_each3(F.getSpecializeAttrs(), SpecializedFuncs, ReInfoVec,
|
for_each3(F.getSpecializeAttrs(), SpecializedFuncs, ReInfoVec,
|
||||||
[&](const SILSpecializeAttr *SA, SILFunction *NewFunc,
|
[&](const SILSpecializeAttr *SA, SILFunction *NewFunc,
|
||||||
const ReabstractionInfo &ReInfo) {
|
const ReabstractionInfo &ReInfo) {
|
||||||
@@ -763,14 +764,14 @@ void EagerSpecializerTransform::run() {
|
|||||||
EagerDispatch(&F, ReInfo).emitDispatchTo(NewFunc);
|
EagerDispatch(&F, ReInfo).emitDispatchTo(NewFunc);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// Invalidate everything since we delete calls as well as add new
|
||||||
|
// calls and branches.
|
||||||
|
if (Changed) {
|
||||||
|
invalidateAnalysis(&F, SILAnalysis::InvalidationKind::Everything);
|
||||||
|
}
|
||||||
// As specializations are created, the attributes should be removed.
|
// As specializations are created, the attributes should be removed.
|
||||||
F.clearSpecializeAttrs();
|
F.clearSpecializeAttrs();
|
||||||
}
|
}
|
||||||
// Invalidate everything since we delete calls as well as add new
|
|
||||||
// calls and branches.
|
|
||||||
if (Changed) {
|
|
||||||
invalidateAnalysis(SILAnalysis::InvalidationKind::Everything);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SILTransform *swift::createEagerSpecializer() {
|
SILTransform *swift::createEagerSpecializer() {
|
||||||
|
|||||||
@@ -934,7 +934,7 @@ class SILGlobalOptPass : public SILModuleTransform
|
|||||||
void run() override {
|
void run() override {
|
||||||
DominanceAnalysis *DA = PM->getAnalysis<DominanceAnalysis>();
|
DominanceAnalysis *DA = PM->getAnalysis<DominanceAnalysis>();
|
||||||
if (SILGlobalOpt(getModule(), DA).run()) {
|
if (SILGlobalOpt(getModule(), DA).run()) {
|
||||||
invalidateAnalysis(SILAnalysis::InvalidationKind::FunctionBody);
|
invalidateAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,6 +103,8 @@ class GlobalPropertyOpt {
|
|||||||
/// All found calls to get-property semantic functions.
|
/// All found calls to get-property semantic functions.
|
||||||
std::vector<ApplyInst *> propertyCalls;
|
std::vector<ApplyInst *> propertyCalls;
|
||||||
|
|
||||||
|
llvm::SetVector<SILFunction *> ChangedFunctions;
|
||||||
|
|
||||||
/// Contains entries with a false property value, which must be propagated
|
/// Contains entries with a false property value, which must be propagated
|
||||||
/// to their dependencies.
|
/// to their dependencies.
|
||||||
llvm::SmallVector<Entry *, 32> WorkList;
|
llvm::SmallVector<Entry *, 32> WorkList;
|
||||||
@@ -223,13 +225,13 @@ class GlobalPropertyOpt {
|
|||||||
|
|
||||||
void propagatePropertiesInGraph();
|
void propagatePropertiesInGraph();
|
||||||
|
|
||||||
bool replacePropertyCalls();
|
void replacePropertyCalls();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GlobalPropertyOpt(SILModule &Module) :
|
GlobalPropertyOpt(SILModule &Module) :
|
||||||
M(Module), ArrayType(nullptr) {}
|
M(Module), ArrayType(nullptr) {}
|
||||||
|
|
||||||
bool run();
|
void run(SILModuleTransform *T);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Checks if an address value does escape. If \p acceptStore is false, then
|
/// Checks if an address value does escape. If \p acceptStore is false, then
|
||||||
@@ -453,13 +455,15 @@ void GlobalPropertyOpt::propagatePropertiesInGraph() {
|
|||||||
|
|
||||||
/// Replaces all get-property calls, which we can prove to be true, with
|
/// Replaces all get-property calls, which we can prove to be true, with
|
||||||
/// true-literals.
|
/// true-literals.
|
||||||
bool GlobalPropertyOpt::replacePropertyCalls() {
|
void GlobalPropertyOpt::replacePropertyCalls() {
|
||||||
bool Changed = false;
|
|
||||||
for (ApplyInst *AI : propertyCalls) {
|
for (ApplyInst *AI : propertyCalls) {
|
||||||
|
SILFunction *F = AI->getFunction();
|
||||||
// Don't optimize functions that are marked with the opt.never attribute.
|
// Don't optimize functions that are marked with the opt.never attribute.
|
||||||
if (!AI->getFunction()->shouldOptimize())
|
if (!F->shouldOptimize())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
ChangedFunctions.insert(F);
|
||||||
|
|
||||||
SILValue array = AI->getArgument(0);
|
SILValue array = AI->getArgument(0);
|
||||||
|
|
||||||
// Is the argument a native swift array?
|
// Is the argument a native swift array?
|
||||||
@@ -481,14 +485,12 @@ bool GlobalPropertyOpt::replacePropertyCalls() {
|
|||||||
|
|
||||||
semCall.removeCall();
|
semCall.removeCall();
|
||||||
NumPropertiesReplaced++;
|
NumPropertiesReplaced++;
|
||||||
Changed = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Changed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The main entry point to the optimization.
|
/// The main entry point to the optimization.
|
||||||
bool GlobalPropertyOpt::run() {
|
void GlobalPropertyOpt::run(SILModuleTransform *T) {
|
||||||
|
|
||||||
assert(WorkList.empty());
|
assert(WorkList.empty());
|
||||||
assert(FieldEntries.empty() && ValueEntries.empty());
|
assert(FieldEntries.empty() && ValueEntries.empty());
|
||||||
@@ -502,7 +504,12 @@ bool GlobalPropertyOpt::run() {
|
|||||||
propagatePropertiesInGraph();
|
propagatePropertiesInGraph();
|
||||||
|
|
||||||
// Step 3: replace get-property calls with literals.
|
// Step 3: replace get-property calls with literals.
|
||||||
return replacePropertyCalls();
|
replacePropertyCalls();
|
||||||
|
|
||||||
|
for (SILFunction *ChangedFn : ChangedFunctions) {
|
||||||
|
T->invalidateAnalysis(ChangedFn,
|
||||||
|
SILAnalysis::InvalidationKind::CallsAndInstructions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The module pass, which runs the optimization.
|
/// The module pass, which runs the optimization.
|
||||||
@@ -513,11 +520,7 @@ class GlobalPropertyOptPass : public SILModuleTransform {
|
|||||||
|
|
||||||
DEBUG(llvm::dbgs() << "** GlobalPropertyOpt **\n");
|
DEBUG(llvm::dbgs() << "** GlobalPropertyOpt **\n");
|
||||||
|
|
||||||
bool Changed = GlobalPropertyOpt(*M).run();
|
GlobalPropertyOpt(*M).run(this);
|
||||||
|
|
||||||
if (Changed) {
|
|
||||||
invalidateAnalysis(SILAnalysis::InvalidationKind::CallsAndInstructions);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef getName() override { return "GlobalPropertyOpt"; }
|
StringRef getName() override { return "GlobalPropertyOpt"; }
|
||||||
|
|||||||
@@ -43,11 +43,12 @@ namespace {
|
|||||||
|
|
||||||
class LetPropertiesOpt {
|
class LetPropertiesOpt {
|
||||||
SILModule *Module;
|
SILModule *Module;
|
||||||
bool HasChanged = false;
|
|
||||||
|
|
||||||
typedef SmallVector<SILInstruction *, 8> Instructions;
|
typedef SmallVector<SILInstruction *, 8> Instructions;
|
||||||
typedef SmallVector<VarDecl *, 4> Properties;
|
typedef SmallVector<VarDecl *, 4> Properties;
|
||||||
|
|
||||||
|
llvm::SetVector<SILFunction *> ChangedFunctions;
|
||||||
|
|
||||||
// Map each let property to a set of instructions accessing it.
|
// Map each let property to a set of instructions accessing it.
|
||||||
llvm::MapVector<VarDecl *, Instructions> AccessMap;
|
llvm::MapVector<VarDecl *, Instructions> AccessMap;
|
||||||
// Map each let property to the instruction sequence which initializes it.
|
// Map each let property to the instruction sequence which initializes it.
|
||||||
@@ -69,7 +70,7 @@ class LetPropertiesOpt {
|
|||||||
public:
|
public:
|
||||||
LetPropertiesOpt(SILModule *M): Module(M) {}
|
LetPropertiesOpt(SILModule *M): Module(M) {}
|
||||||
|
|
||||||
bool run();
|
void run(SILModuleTransform *T);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool isConstantLetProperty(VarDecl *Property);
|
bool isConstantLetProperty(VarDecl *Property);
|
||||||
@@ -188,12 +189,14 @@ void LetPropertiesOpt::optimizeLetPropertyAccess(VarDecl *Property,
|
|||||||
unsigned NumReplaced = 0;
|
unsigned NumReplaced = 0;
|
||||||
|
|
||||||
for (auto Load: Loads) {
|
for (auto Load: Loads) {
|
||||||
|
SILFunction *F = Load->getFunction();
|
||||||
|
|
||||||
// Look for any instructions accessing let properties.
|
// Look for any instructions accessing let properties.
|
||||||
if (isa<RefElementAddrInst>(Load)) {
|
if (isa<RefElementAddrInst>(Load)) {
|
||||||
// Copy the initializer into the function
|
// Copy the initializer into the function
|
||||||
// Replace the access to a let property by the value
|
// Replace the access to a let property by the value
|
||||||
// computed by this initializer.
|
// computed by this initializer.
|
||||||
InstructionsCloner Cloner(*Load->getFunction(), Init, Load);
|
InstructionsCloner Cloner(*F, Init, Load);
|
||||||
Cloner.clone();
|
Cloner.clone();
|
||||||
SILInstruction *I = &*std::prev(Load->getIterator());
|
SILInstruction *I = &*std::prev(Load->getIterator());
|
||||||
SILBuilderWithScope B(Load);
|
SILBuilderWithScope B(Load);
|
||||||
@@ -208,12 +211,12 @@ void LetPropertiesOpt::optimizeLetPropertyAccess(VarDecl *Property,
|
|||||||
User->eraseFromParent();
|
User->eraseFromParent();
|
||||||
++NumReplaced;
|
++NumReplaced;
|
||||||
}
|
}
|
||||||
HasChanged = true;
|
ChangedFunctions.insert(F);
|
||||||
} else if (isa<StructExtractInst>(Load)) {
|
} else if (isa<StructExtractInst>(Load)) {
|
||||||
// Copy the initializer into the function
|
// Copy the initializer into the function
|
||||||
// Replace the access to a let property by the value
|
// Replace the access to a let property by the value
|
||||||
// computed by this initializer.
|
// computed by this initializer.
|
||||||
InstructionsCloner Cloner(*Load->getFunction(), Init, Load);
|
InstructionsCloner Cloner(*F, Init, Load);
|
||||||
Cloner.clone();
|
Cloner.clone();
|
||||||
SILInstruction *I = &*std::prev(Load->getIterator());
|
SILInstruction *I = &*std::prev(Load->getIterator());
|
||||||
Load->replaceAllUsesWith(I);
|
Load->replaceAllUsesWith(I);
|
||||||
@@ -222,12 +225,12 @@ void LetPropertiesOpt::optimizeLetPropertyAccess(VarDecl *Property,
|
|||||||
|
|
||||||
Load->eraseFromParent();
|
Load->eraseFromParent();
|
||||||
++NumReplaced;
|
++NumReplaced;
|
||||||
HasChanged = true;
|
ChangedFunctions.insert(F);
|
||||||
} else if (isa<StructElementAddrInst>(Load)) {
|
} else if (isa<StructElementAddrInst>(Load)) {
|
||||||
// Copy the initializer into the function
|
// Copy the initializer into the function
|
||||||
// Replace the access to a let property by the value
|
// Replace the access to a let property by the value
|
||||||
// computed by this initializer.
|
// computed by this initializer.
|
||||||
InstructionsCloner Cloner(*Load->getFunction(), Init, Load);
|
InstructionsCloner Cloner(*F, Init, Load);
|
||||||
Cloner.clone();
|
Cloner.clone();
|
||||||
SILInstruction *I = &*std::prev(Load->getIterator());
|
SILInstruction *I = &*std::prev(Load->getIterator());
|
||||||
SILBuilderWithScope B(Load);
|
SILBuilderWithScope B(Load);
|
||||||
@@ -241,7 +244,7 @@ void LetPropertiesOpt::optimizeLetPropertyAccess(VarDecl *Property,
|
|||||||
User->eraseFromParent();
|
User->eraseFromParent();
|
||||||
++NumReplaced;
|
++NumReplaced;
|
||||||
}
|
}
|
||||||
HasChanged = true;
|
ChangedFunctions.insert(F);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,7 +566,7 @@ void LetPropertiesOpt::collectPropertyAccess(SILInstruction *I,
|
|||||||
CannotRemove.insert(Property);
|
CannotRemove.insert(Property);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LetPropertiesOpt::run() {
|
void LetPropertiesOpt::run(SILModuleTransform *T) {
|
||||||
// Collect property access information for the whole module.
|
// Collect property access information for the whole module.
|
||||||
for (auto &F : *Module) {
|
for (auto &F : *Module) {
|
||||||
// Take into account even those functions that should not be
|
// Take into account even those functions that should not be
|
||||||
@@ -593,17 +596,18 @@ bool LetPropertiesOpt::run() {
|
|||||||
optimizeLetPropertyAccess(Init.first, Init.second);
|
optimizeLetPropertyAccess(Init.first, Init.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
return HasChanged;
|
for (SILFunction *ChangedFn : ChangedFunctions) {
|
||||||
|
// Program flow is not changed by this pass.
|
||||||
|
T->invalidateAnalysis(ChangedFn,
|
||||||
|
SILAnalysis::InvalidationKind::Instructions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class LetPropertiesOptPass : public SILModuleTransform
|
class LetPropertiesOptPass : public SILModuleTransform
|
||||||
{
|
{
|
||||||
void run() override {
|
void run() override {
|
||||||
if (LetPropertiesOpt(getModule()).run()) {
|
LetPropertiesOpt(getModule()).run(this);
|
||||||
// Program flow is not changed by this pass.
|
|
||||||
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef getName() override {
|
StringRef getName() override {
|
||||||
|
|||||||
@@ -1470,7 +1470,7 @@ void AddressLowering::runOnFunction(SILFunction *F) {
|
|||||||
// Rewrite instructions with address-only operands or results.
|
// Rewrite instructions with address-only operands or results.
|
||||||
rewriteFunction(pass);
|
rewriteFunction(pass);
|
||||||
|
|
||||||
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
|
invalidateAnalysis(F, SILAnalysis::InvalidationKind::Instructions);
|
||||||
|
|
||||||
// Instructions that were explicitly marked dead should already have no
|
// Instructions that were explicitly marked dead should already have no
|
||||||
// users.
|
// users.
|
||||||
|
|||||||
@@ -727,7 +727,8 @@ static bool removeUnreachableBlocks(SILFunction &F, SILModule &M,
|
|||||||
/// diagnose any user code after it as being unreachable. This pass happens
|
/// diagnose any user code after it as being unreachable. This pass happens
|
||||||
/// before the definite initialization pass so that it doesn't see infeasible
|
/// before the definite initialization pass so that it doesn't see infeasible
|
||||||
/// control flow edges.
|
/// control flow edges.
|
||||||
static void performNoReturnFunctionProcessing(SILModule *M) {
|
static void performNoReturnFunctionProcessing(SILModule *M,
|
||||||
|
SILModuleTransform *T) {
|
||||||
for (auto &Fn : *M) {
|
for (auto &Fn : *M) {
|
||||||
DEBUG(llvm::errs() << "*** No return function processing: "
|
DEBUG(llvm::errs() << "*** No return function processing: "
|
||||||
<< Fn.getName() << "\n");
|
<< Fn.getName() << "\n");
|
||||||
@@ -737,10 +738,11 @@ static void performNoReturnFunctionProcessing(SILModule *M) {
|
|||||||
// function.
|
// function.
|
||||||
simplifyBlocksWithCallsToNoReturn(BB, nullptr);
|
simplifyBlocksWithCallsToNoReturn(BB, nullptr);
|
||||||
}
|
}
|
||||||
|
T->invalidateAnalysis(&Fn, SILAnalysis::InvalidationKind::FunctionBody);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void swift::performSILDiagnoseUnreachable(SILModule *M) {
|
void swift::performSILDiagnoseUnreachable(SILModule *M, SILModuleTransform *T) {
|
||||||
for (auto &Fn : *M) {
|
for (auto &Fn : *M) {
|
||||||
DEBUG(llvm::errs() << "*** Diagnose Unreachable processing: "
|
DEBUG(llvm::errs() << "*** Diagnose Unreachable processing: "
|
||||||
<< Fn.getName() << "\n");
|
<< Fn.getName() << "\n");
|
||||||
@@ -778,14 +780,16 @@ void swift::performSILDiagnoseUnreachable(SILModule *M) {
|
|||||||
|
|
||||||
// Remove unreachable blocks.
|
// Remove unreachable blocks.
|
||||||
removeUnreachableBlocks(Fn, *M, &State);
|
removeUnreachableBlocks(Fn, *M, &State);
|
||||||
|
|
||||||
|
if (T)
|
||||||
|
T->invalidateAnalysis(&Fn, SILAnalysis::InvalidationKind::FunctionBody);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class NoReturnFolding : public SILModuleTransform {
|
class NoReturnFolding : public SILModuleTransform {
|
||||||
void run() override {
|
void run() override {
|
||||||
performNoReturnFunctionProcessing(getModule());
|
performNoReturnFunctionProcessing(getModule(), this);
|
||||||
invalidateAnalysis(SILAnalysis::InvalidationKind::FunctionBody);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef getName() override { return "NoReturnFolding"; }
|
StringRef getName() override { return "NoReturnFolding"; }
|
||||||
@@ -800,8 +804,7 @@ SILTransform *swift::createNoReturnFolding() {
|
|||||||
namespace {
|
namespace {
|
||||||
class DiagnoseUnreachable : public SILModuleTransform {
|
class DiagnoseUnreachable : public SILModuleTransform {
|
||||||
void run() override {
|
void run() override {
|
||||||
performSILDiagnoseUnreachable(getModule());
|
performSILDiagnoseUnreachable(getModule(), this);
|
||||||
invalidateAnalysis(SILAnalysis::InvalidationKind::FunctionBody);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef getName() override { return "Diagnose Unreachable"; }
|
StringRef getName() override { return "Diagnose Unreachable"; }
|
||||||
|
|||||||
@@ -557,6 +557,8 @@ class MandatoryInlining : public SILModuleTransform {
|
|||||||
for (auto FI = M->begin(), E = M->end(); FI != E; ) {
|
for (auto FI = M->begin(), E = M->end(); FI != E; ) {
|
||||||
SILFunction &F = *FI++;
|
SILFunction &F = *FI++;
|
||||||
|
|
||||||
|
invalidateAnalysis(&F, SILAnalysis::InvalidationKind::Everything);
|
||||||
|
|
||||||
if (F.getRefCount() != 0) continue;
|
if (F.getRefCount() != 0) continue;
|
||||||
|
|
||||||
// Leave non-transparent functions alone.
|
// Leave non-transparent functions alone.
|
||||||
@@ -572,12 +574,12 @@ class MandatoryInlining : public SILModuleTransform {
|
|||||||
// even if not referenced inside SIL.
|
// even if not referenced inside SIL.
|
||||||
if (F.getRepresentation() == SILFunctionTypeRepresentation::ObjCMethod)
|
if (F.getRepresentation() == SILFunctionTypeRepresentation::ObjCMethod)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
notifyDeleteFunction(&F);
|
||||||
|
|
||||||
// Okay, just erase the function from the module.
|
// Okay, just erase the function from the module.
|
||||||
M->eraseFunction(&F);
|
M->eraseFunction(&F);
|
||||||
}
|
}
|
||||||
|
|
||||||
invalidateAnalysis(SILAnalysis::InvalidationKind::Everything);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef getName() override { return "Mandatory Inlining"; }
|
StringRef getName() override { return "Mandatory Inlining"; }
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ bool Devirtualizer::devirtualizeAppliesInFunction(SILFunction &F,
|
|||||||
// be beneficial to rerun some earlier passes on the current
|
// be beneficial to rerun some earlier passes on the current
|
||||||
// function now that we've made these direct references visible.
|
// function now that we've made these direct references visible.
|
||||||
if (CalleeFn->isDefinition() && CalleeFn->shouldOptimize())
|
if (CalleeFn->isDefinition() && CalleeFn->shouldOptimize())
|
||||||
notifyPassManagerOfFunction(CalleeFn, nullptr);
|
notifyAddFunction(CalleeFn, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Changed;
|
return Changed;
|
||||||
|
|||||||
@@ -981,11 +981,11 @@ public:
|
|||||||
// The old function must be a thunk now.
|
// The old function must be a thunk now.
|
||||||
assert(F->isThunk() && "Old function should have been turned into a thunk");
|
assert(F->isThunk() && "Old function should have been turned into a thunk");
|
||||||
|
|
||||||
PM->invalidateAnalysis(F, SILAnalysis::InvalidationKind::Everything);
|
invalidateAnalysis(SILAnalysis::InvalidationKind::Everything);
|
||||||
|
|
||||||
// Make sure the PM knows about this function. This will also help us
|
// Make sure the PM knows about this function. This will also help us
|
||||||
// with self-recursion.
|
// with self-recursion.
|
||||||
notifyPassManagerOfFunction(FST.getOptimizedFunction(), F);
|
notifyAddFunction(FST.getOptimizedFunction(), F);
|
||||||
|
|
||||||
if (!OptForPartialApply) {
|
if (!OptForPartialApply) {
|
||||||
// We have to restart the pipeline for this thunk in order to run the
|
// We have to restart the pipeline for this thunk in order to run the
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ bool GenericSpecializer::specializeAppliesInFunction(SILFunction &F) {
|
|||||||
// (as opposed to returning a previous specialization), we need to notify
|
// (as opposed to returning a previous specialization), we need to notify
|
||||||
// the pass manager so that the new functions get optimized.
|
// the pass manager so that the new functions get optimized.
|
||||||
for (SILFunction *NewF : reverse(NewFunctions)) {
|
for (SILFunction *NewF : reverse(NewFunctions)) {
|
||||||
notifyPassManagerOfFunction(NewF, Callee);
|
notifyAddFunction(NewF, Callee);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class SILLinker : public SILModuleTransform {
|
|||||||
SILModule &M = *getModule();
|
SILModule &M = *getModule();
|
||||||
for (auto &Fn : M)
|
for (auto &Fn : M)
|
||||||
if (M.linkFunction(&Fn, SILModule::LinkingMode::LinkAll))
|
if (M.linkFunction(&Fn, SILModule::LinkingMode::LinkAll))
|
||||||
invalidateAnalysis(&Fn, SILAnalysis::InvalidationKind::Everything);
|
invalidateAnalysis(&Fn, SILAnalysis::InvalidationKind::Everything);
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef getName() override { return "SIL Linker"; }
|
StringRef getName() override { return "SIL Linker"; }
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace {
|
|||||||
|
|
||||||
class LoopRegionViewText : public SILModuleTransform {
|
class LoopRegionViewText : public SILModuleTransform {
|
||||||
void run() override {
|
void run() override {
|
||||||
invalidateAnalysis(SILAnalysis::InvalidationKind::Everything);
|
invalidateAll();
|
||||||
LoopRegionAnalysis *LRA = PM->getAnalysis<LoopRegionAnalysis>();
|
LoopRegionAnalysis *LRA = PM->getAnalysis<LoopRegionAnalysis>();
|
||||||
for (auto &Fn : *getModule()) {
|
for (auto &Fn : *getModule()) {
|
||||||
if (Fn.isExternalDeclaration()) continue;
|
if (Fn.isExternalDeclaration()) continue;
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ void removeUnwantedFunctions(SILModule *M, ArrayRef<std::string> MangledNames,
|
|||||||
// After running this pass all of the functions we will remove
|
// After running this pass all of the functions we will remove
|
||||||
// should consist only of one basic block terminated by
|
// should consist only of one basic block terminated by
|
||||||
// UnreachableInst.
|
// UnreachableInst.
|
||||||
performSILDiagnoseUnreachable(M);
|
performSILDiagnoseUnreachable(M, nullptr);
|
||||||
|
|
||||||
// Now mark all of these functions as public and remove their bodies.
|
// Now mark all of these functions as public and remove their bodies.
|
||||||
for (auto &F : DeadFunctions) {
|
for (auto &F : DeadFunctions) {
|
||||||
|
|||||||
Reference in New Issue
Block a user