//===- BasicCalleeAnalysis.h - Determine callees per call site --*- C++ -*-===// // // 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 // //===----------------------------------------------------------------------===// #ifndef SWIFT_SILOPTIMIZER_ANALYSIS_BASICCALLEEANALYSIS_H #define SWIFT_SILOPTIMIZER_ANALYSIS_BASICCALLEEANALYSIS_H #include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/ApplySite.h" #include "swift/SIL/SILModule.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/Allocator.h" namespace swift { class ClassDecl; class SILFunction; class SILModule; class SILWitnessTable; /// CalleeList is a data structure representing the list of potential /// callees at a particular apply site. It also has a query that /// allows a client to determine whether the list is incomplete in the /// sense that there may be unrepresented callees. class CalleeList { llvm::TinyPtrVector CalleeFunctions; bool IsIncomplete; public: /// Constructor for when we know nothing about the callees and must /// assume the worst. CalleeList() : IsIncomplete(true) {} /// Constructor for the case where we know an apply can target only /// a single function. CalleeList(SILFunction *F) : CalleeFunctions(F), IsIncomplete(false) {} /// Constructor for arbitrary lists of callees. CalleeList(llvm::SmallVectorImpl &List, bool IsIncomplete) : CalleeFunctions(llvm::makeArrayRef(List.begin(), List.end())), IsIncomplete(IsIncomplete) {} /// Return an iterator for the beginning of the list. ArrayRef::iterator begin() const { return CalleeFunctions.begin(); } /// Return an iterator for the end of the list. ArrayRef::iterator end() const { return CalleeFunctions.end(); } bool isIncomplete() const { return IsIncomplete; } /// Returns true if all callees are known and not external. bool allCalleesVisible(); }; /// CalleeCache is a helper class that builds lists of potential /// callees for class and witness method applications, and provides an /// interface for retrieving a (possibly incomplete) CalleeList for /// any function application site (including those that are simple /// function_ref, thin_to_thick, or partial_apply callees). class CalleeCache { using Callees = llvm::SmallVector; using CalleesAndCanCallUnknown = llvm::PointerIntPair; using CacheType = llvm::DenseMap; SILModule &M; // Allocator for the SmallVectors that we will be allocating. llvm::SpecificBumpPtrAllocator Allocator; // The cache of precomputed callee lists for function decls appearing // in class virtual dispatch tables and witness tables. CacheType TheCache; public: CalleeCache(SILModule &M) : M(M) { computeMethodCallees(); sortAndUniqueCallees(); } ~CalleeCache() { Allocator.DestroyAll(); } /// Return the list of callees that can potentially be called at the /// given apply site. CalleeList getCalleeList(FullApplySite FAS) const; /// Return the list of callees that can potentially be called at the /// given instruction. E.g. it could be destructors. CalleeList getCalleeList(SILInstruction *I) const; private: void enumerateFunctionsInModule(); void sortAndUniqueCallees(); CalleesAndCanCallUnknown &getOrCreateCalleesForMethod(SILDeclRef Decl); void computeClassMethodCalleesForClass(ClassDecl *CD); void computeClassMethodCallees(ClassDecl *CD, SILDeclRef Method); void computeWitnessMethodCalleesForWitnessTable(SILWitnessTable &WT); void computeMethodCallees(); SILFunction *getSingleCalleeForWitnessMethod(WitnessMethodInst *WMI) const; CalleeList getCalleeList(SILDeclRef Decl) const; CalleeList getCalleeList(WitnessMethodInst *WMI) const; CalleeList getCalleeList(ClassMethodInst *CMI) const; CalleeList getCalleeListForCalleeKind(SILValue Callee) const; }; class BasicCalleeAnalysis : public SILAnalysis { SILModule &M; std::unique_ptr Cache; public: BasicCalleeAnalysis(SILModule *M) : SILAnalysis(SILAnalysisKind::BasicCallee), M(*M), Cache(nullptr) {} static bool classof(const SILAnalysis *S) { return S->getKind() == SILAnalysisKind::BasicCallee; } /// Invalidate all information in this analysis. virtual void invalidate() override { Cache.reset(); } /// Invalidate all of the information for a specific function. virtual void invalidate(SILFunction *F, InvalidationKind K) override { // No invalidation needed because the analysis does not cache anything // per call-site in functions. } /// Notify the analysis about a newly created function. virtual void notifyAddedOrModifiedFunction(SILFunction *F) override { // Nothing to be done because the analysis does not cache anything // per call-site in functions. } /// Notify the analysis about a function which will be deleted from the /// module. virtual void notifyWillDeleteFunction(SILFunction *F) override { // No invalidation needed because the analysis does not cache anything per // call-site in functions. } /// Notify the analysis about changed witness or vtables. virtual void invalidateFunctionTables() override { Cache.reset(); } CalleeList getCalleeList(FullApplySite FAS) { if (!Cache) Cache = llvm::make_unique(M); return Cache->getCalleeList(FAS); } CalleeList getCalleeList(SILInstruction *I) { if (!Cache) Cache = llvm::make_unique(M); return Cache->getCalleeList(I); } }; } // end namespace swift #endif