-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Improve sil_combiner using subtyping information from CHA #16739
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
#ifndef SWIFT_SILOPTIMIZER_ANALYSIS_CONCRETETYPE_H | ||
#define SWIFT_SILOPTIMIZER_ANALYSIS_CONCRETETYPE_H | ||
|
||
#include "swift/SIL/SILArgument.h" | ||
#include "swift/SIL/SILValue.h" | ||
#include "swift/SILOptimizer/Analysis/Analysis.h" | ||
#include "llvm/ADT/DenseMap.h" | ||
#include "llvm/ADT/SmallSet.h" | ||
#include "llvm/ADT/SmallVector.h" | ||
#include "llvm/Support/Debug.h" | ||
|
||
namespace swift { | ||
|
||
class SILModule; | ||
class NominalTypeDecl; | ||
class ProtocolDecl; | ||
|
||
class ConcreteTypeAnalysis : public SILAnalysis { | ||
public: | ||
typedef SmallVector<NominalTypeDecl *, 8> NominalTypeList; | ||
typedef llvm::DenseMap<ProtocolDecl *, NominalTypeDecl *> | ||
ProtocolSoleTypeImplementation; | ||
typedef llvm::DenseMap<ProtocolDecl *, NominalTypeList> | ||
ProtocolImplementations; | ||
|
||
ConcreteTypeAnalysis(SILModule *Mod) | ||
: SILAnalysis(AnalysisKind::ConcreteType), M(Mod) { | ||
init(); | ||
} | ||
|
||
~ConcreteTypeAnalysis(); | ||
|
||
static bool classof(const SILAnalysis *S) { | ||
return S->getKind() == AnalysisKind::ConcreteType; | ||
} | ||
|
||
/// 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 {} | ||
|
||
/// 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 {} | ||
|
||
/// Get the sole class that implements a protocol. | ||
NominalTypeDecl *getSoleTypeImplementingProtocol(ProtocolDecl *P) { | ||
return ProtocolSoleTypeImplementationCache[P]; | ||
} | ||
|
||
private: | ||
/// Compute inheritance properties. | ||
void init(); | ||
|
||
/// The module. | ||
SILModule *M; | ||
|
||
/// A cache that maps a protocol to its sole class conforming to it. | ||
ProtocolSoleTypeImplementation ProtocolSoleTypeImplementationCache; | ||
}; | ||
|
||
} // namespace swift | ||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
//===--- ConcreteTypeAnalysis.cpp - Protocol to Class inheritance ---------===// | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Word "Class" should not appear here, and maybe rename this to "ProtocolConfomanceAnalysis" in general we use "X conforms to Y" instead of "X implements Y" |
||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors | ||
// Licensed under Apache License v2.0 with Runtime Library Exception | ||
// | ||
// See https://swift.org/LICENSE.txt for license information | ||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "swift/SILOptimizer/Analysis/ConcreteTypeAnalysis.h" | ||
#include "swift/AST/ASTContext.h" | ||
#include "swift/AST/ASTWalker.h" | ||
#include "swift/AST/Module.h" | ||
#include "swift/SIL/SILInstruction.h" | ||
#include "swift/SIL/SILModule.h" | ||
#include "swift/SIL/SILValue.h" | ||
|
||
using namespace swift; | ||
|
||
namespace { | ||
/// A helper class to collect all nominal type declarations. | ||
class NominalTypeWalker : public ASTWalker { | ||
ConcreteTypeAnalysis::ProtocolImplementations &ProtocolImplementationsCache; | ||
|
||
public: | ||
NominalTypeWalker(ConcreteTypeAnalysis::ProtocolImplementations | ||
&ProtocolImplementationsCache) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line this up with the ( |
||
: ProtocolImplementationsCache(ProtocolImplementationsCache) {} | ||
|
||
bool walkToDeclPre(Decl *D) override { | ||
auto *NTD = dyn_cast<NominalTypeDecl>(D); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We tend to write |
||
if (!NTD || !NTD->hasInterfaceType()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NTD should have an interface type |
||
return true; | ||
auto Protocols = NTD->getAllProtocols(); | ||
// We are only interested in types implementing protocols. | ||
if (!Protocols.empty()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the protocols are empty, the loop does nothing, so we can remove this |
||
for (auto &Protocol : Protocols) { | ||
auto &K = ProtocolImplementationsCache[Protocol]; | ||
K.push_back(NTD); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Combine this line with the previous |
||
} | ||
} | ||
return true; | ||
} | ||
}; | ||
} // end anonymous namespace | ||
|
||
void ConcreteTypeAnalysis::init() { | ||
|
||
// We only do this in Whole-Module compilation mode. | ||
if (!(M->isWholeModule())) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extra parens |
||
return; | ||
|
||
// Process all types implementing protocols. | ||
SmallVector<Decl *, 32> Decls; | ||
|
||
// Store protocols and thier implementations in a dense map. | ||
ProtocolImplementations ProtocolImplementationsCache; | ||
|
||
M->getSwiftModule()->getTopLevelDecls(Decls); | ||
|
||
/// This operation is quadratic and should only be performed | ||
/// in whole module compilation. | ||
NominalTypeWalker Walker(ProtocolImplementationsCache); | ||
for (auto *D : Decls) { | ||
D->walk(Walker); | ||
} | ||
|
||
for (auto *D : Decls) { | ||
auto ProtoDecl = dyn_cast<ProtocolDecl>(D); | ||
/// Check for protocols that are either internal or lower with whole module | ||
/// compilation enabled. | ||
if (ProtoDecl && ProtoDecl->hasAccess() && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hasAccess() will always be true in WMO |
||
ProtocolImplementationsCache.count(ProtoDecl) && | ||
(ProtoDecl->getEffectiveAccess() <= AccessLevel::Internal)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Turn this into a negated condition with a 'continue' |
||
|
||
/// Make sure one class/enum/struct implements this protocol. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The reverse mapping should store all conforming types, not just one |
||
SmallVector<NominalTypeDecl *, 8> ImplementedDeclList = | ||
ProtocolImplementationsCache[ProtoDecl]; | ||
/// Bail if more than one type implements the protocol. | ||
if (ImplementedDeclList.size() > 1) | ||
continue; | ||
auto NTD = *(ImplementedDeclList.begin()); | ||
/// Check the access level. | ||
if (NTD->getEffectiveAccess() > AccessLevel::Internal) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is an unnecessary restriction |
||
continue; | ||
|
||
/// Check if it is a class/struct/enum. | ||
if (isa<ClassDecl>(NTD) || isa<StructDecl>(NTD) || isa<EnumDecl>(NTD)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this is necessary |
||
ProtocolSoleTypeImplementationCache[ProtoDecl] = NTD; | ||
} | ||
} | ||
} | ||
} | ||
|
||
ConcreteTypeAnalysis::~ConcreteTypeAnalysis() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,8 @@ | |
#include "swift/SIL/SILValue.h" | ||
#include "swift/SIL/SILVisitor.h" | ||
#include "swift/SILOptimizer/Utils/CastOptimizer.h" | ||
#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h" | ||
#include "swift/SILOptimizer/Analysis/ConcreteTypeAnalysis.h" | ||
#include "swift/SILOptimizer/Utils/Local.h" | ||
#include "llvm/ADT/DenseMap.h" | ||
#include "llvm/ADT/SmallVector.h" | ||
|
@@ -117,6 +119,10 @@ class SILCombiner : | |
|
||
DominanceAnalysis *DA; | ||
|
||
ConcreteTypeAnalysis *CTA; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be nice to add comments here explaining why these are used? |
||
|
||
ClassHierarchyAnalysis *CHA; | ||
|
||
/// Worklist containing all of the instructions primed for simplification. | ||
SILCombineWorklist Worklist; | ||
|
||
|
@@ -135,10 +141,14 @@ class SILCombiner : | |
/// Cast optimizer | ||
CastOptimizer CastOpt; | ||
|
||
/// Set of ApplySites instrumented by concrete type analysis. | ||
llvm::DenseSet<FullApplySite> VisitedAIForCTA; | ||
|
||
public: | ||
SILCombiner(SILBuilder &B, AliasAnalysis *AA, DominanceAnalysis *DA, | ||
ConcreteTypeAnalysis *CTA, ClassHierarchyAnalysis *CHA, | ||
bool removeCondFails) | ||
: AA(AA), DA(DA), Worklist(), MadeChange(false), | ||
: AA(AA), DA(DA), CTA(CTA), CHA(CHA), Worklist(), MadeChange(false), | ||
RemoveCondFails(removeCondFails), Iteration(0), Builder(B), | ||
CastOpt(/* ReplaceInstUsesAction */ | ||
[&](SingleValueInstruction *I, ValueBase *V) { | ||
|
@@ -295,6 +305,13 @@ class SILCombiner : | |
WitnessMethodInst *WMI); | ||
SILInstruction *propagateConcreteTypeOfInitExistential(FullApplySite AI); | ||
|
||
/// Propagate concrete types from concrete type analysis. | ||
SILInstruction *propagateConcreteTypeFromCTA(FullApplySite AI); | ||
bool propagateConcreteTypeFromCTAInternal( | ||
FullApplySite Apply, ProtocolDecl *Protocol, SILValue &Arg, | ||
SILValue &NewArg, Optional<ProtocolConformanceRef> &ConformanceRef, | ||
ArchetypeType *OpenedArchetype, CanType &ConcreteType); | ||
|
||
/// Perform one SILCombine iteration. | ||
bool doOneIteration(SILFunction &F, unsigned Iteration); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs a file header.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!