blob: 1c19552cd5f5fcb613fc3b3693387d335148a6a1 [file] [log] [blame]
//===--- AccessSummaryAnalysis.h - SIL Access Summary Analysis --*- 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
//
//===----------------------------------------------------------------------===//
//
// This file implements an interprocedural analysis pass that summarizes
// the formal accesses that a function makes to its address-type arguments.
// These summaries are used to statically diagnose violations of exclusive
// accesses for noescape closures.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SILOPTIMIZER_ANALYSIS_ACCESS_SUMMARY_ANALYSIS_H_
#define SWIFT_SILOPTIMIZER_ANALYSIS_ACCESS_SUMMARY_ANALYSIS_H_
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SILOptimizer/Analysis/BottomUpIPAnalysis.h"
#include "swift/SILOptimizer/Utils/IndexTrie.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
namespace swift {
class AccessSummaryAnalysis : public BottomUpIPAnalysis {
public:
class SubAccessSummary {
private:
/// The kind of access begun on the argument.
SILAccessKind Kind;
/// The location of the access. Used for diagnostics.
SILLocation AccessLoc = SILLocation((Expr *)nullptr);
const IndexTrieNode *SubPath = nullptr;
public:
SubAccessSummary(SILAccessKind Kind, SILLocation AccessLoc,
const IndexTrieNode *SubPath)
: Kind(Kind), AccessLoc(AccessLoc), SubPath(SubPath) {}
SILAccessKind getAccessKind() const { return Kind; }
SILLocation getAccessLoc() const { return AccessLoc; }
const IndexTrieNode *getSubPath() const { return SubPath; }
/// The lattice operation on SubAccessSummaries summaries.
bool mergeWith(const SubAccessSummary &other);
/// Merge in an access to the argument of the given kind at the given
/// location with the given suppath. Returns true if the merge caused the
/// summary to change.
bool mergeWith(SILAccessKind otherKind, SILLocation otherLoc,
const IndexTrieNode *otherSubPath);
/// Returns a description of the summary. For debugging and testing
/// purposes.
std::string getDescription(SILType BaseType, SILModule &M) const;
};
typedef llvm::SmallDenseMap<const IndexTrieNode *, SubAccessSummary, 8>
SubAccessMap;
/// Summarizes the accesses that a function begins on an argument, including
/// the projection subpath that was accessed.
class ArgumentSummary {
private:
SubAccessMap SubAccesses;
public:
/// The lattice operation on argument summaries.
bool mergeWith(const ArgumentSummary &other);
/// Merge in an access to the argument of the given kind at the given
/// location. Returns true if the merge caused the summary to change.
bool mergeWith(SILAccessKind otherKind, SILLocation otherLoc,
const IndexTrieNode *otherSubPath);
/// Returns a description of the summary. For debugging and testing
/// purposes.
std::string getDescription(SILType BaseType, SILModule &M) const;
/// Returns the accesses that the function performs to subpaths of the
/// argument.
const SubAccessMap &getSubAccesses() const { return SubAccesses; }
/// Returns the sorted subaccess summaries into the passed-in storage.
/// The accesses are sorted lexicographically by increasing subpath
/// length and projection index.
void getSortedSubAccesses(SmallVectorImpl<SubAccessSummary> &storage) const;
};
/// Summarizes the accesses that a function begins on its arguments or
/// projections from its arguments.
class FunctionSummary {
private:
llvm::SmallVector<ArgumentSummary, 6> ArgAccesses;
public:
FunctionSummary(unsigned argCount) : ArgAccesses(argCount) {}
/// Returns of summary of the the function accesses that argument at the
/// given index.
ArgumentSummary &getAccessForArgument(unsigned argument) {
return ArgAccesses[argument];
}
const ArgumentSummary &getAccessForArgument(unsigned argument) const {
return ArgAccesses[argument];
}
/// Returns the number of argument in the summary.
unsigned getArgumentCount() const { return ArgAccesses.size(); }
void print(raw_ostream &os, SILFunction *fn) const;
};
class FunctionInfo;
/// Records a flow of a caller's argument to a called function.
/// This flow is used to iterate the interprocedural analysis to a fixpoint.
struct ArgumentFlow {
/// The index of the argument in the caller.
const unsigned CallerArgumentIndex;
/// The index of the argument in the callee.
const unsigned CalleeArgumentIndex;
FunctionInfo *const CalleeFunctionInfo;
};
/// Records the summary and argument flows for a given function.
/// Used by the BottomUpIPAnalysis to propagate information
/// from callees to callers.
class FunctionInfo : public FunctionInfoBase<FunctionInfo> {
private:
FunctionSummary FS;
SILFunction *F;
llvm::SmallVector<ArgumentFlow, 8> RecordedArgumentFlows;
public:
FunctionInfo(SILFunction *F) : FS(F->getArguments().size()), F(F) {}
SILFunction *getFunction() const { return F; }
ArrayRef<ArgumentFlow> getArgumentFlows() const {
return RecordedArgumentFlows;
}
const FunctionSummary &getSummary() const { return FS; }
FunctionSummary &getSummary() { return FS; }
/// Record a flow of an argument in this function to a callee.
void recordFlow(const ArgumentFlow &flow) {
flow.CalleeFunctionInfo->addCaller(this, nullptr);
RecordedArgumentFlows.push_back(flow);
}
};
private:
/// Maps functions to the information the analysis keeps for each function.
llvm::DenseMap<SILFunction *, FunctionInfo *> FunctionInfos;
llvm::SpecificBumpPtrAllocator<FunctionInfo> Allocator;
/// A trie of integer indices that gives pointer identity to a path of
/// projections. This is shared between all functions in the module.
std::unique_ptr<IndexTrieNode> SubPathTrie;
public:
AccessSummaryAnalysis() : BottomUpIPAnalysis(SILAnalysisKind::AccessSummary) {
SubPathTrie.reset(new IndexTrieNode());
}
/// Returns a summary of the accesses performed by the given function.
const FunctionSummary &getOrCreateSummary(SILFunction *Fn);
IndexTrieNode *getSubPathTrieRoot() {
return SubPathTrie.get();
}
/// Returns an IndexTrieNode that represents the single subpath accessed from
/// BAI or the root if no such node exists.
const IndexTrieNode *findSubPathAccessed(BeginAccessInst *BAI);
virtual void initialize(SILPassManager *PM) override {}
virtual void invalidate() override;
virtual void invalidate(SILFunction *F, InvalidationKind K) override;
virtual void notifyAddedOrModifiedFunction(SILFunction *F) override {}
virtual void notifyWillDeleteFunction(SILFunction *F) override {
invalidate(F, InvalidationKind::Nothing);
}
virtual void invalidateFunctionTables() override {}
static bool classof(const SILAnalysis *S) {
return S->getKind() == SILAnalysisKind::AccessSummary;
}
/// Returns a description of the subpath suitable for use in diagnostics.
/// The base type must be the type of the root of the path.
static std::string getSubPathDescription(SILType BaseType,
const IndexTrieNode *SubPath,
SILModule &M);
/// Performs a lexicographic comparison of two subpaths, first by path length
/// and then by index of the last path component. Returns true when lhs
/// is less than rhs.
static bool compareSubPaths(const IndexTrieNode *lhs,
const IndexTrieNode *rhs);
private:
typedef BottomUpFunctionOrder<FunctionInfo> FunctionOrder;
/// Returns the BottomUpIPAnalysis information for the given function.
FunctionInfo *getFunctionInfo(SILFunction *F);
/// Summarizes the given function and iterates the interprocedural analysis
/// to a fixpoint.
void recompute(FunctionInfo *initial);
/// Propagate the access summary from the argument of a called function
/// to the caller.
bool propagateFromCalleeToCaller(FunctionInfo *callerInfo,
ArgumentFlow site);
/// Summarize the given function and schedule it for interprocedural
/// analysis.
void processFunction(FunctionInfo *info, FunctionOrder &order);
/// Summarize how the function uses the given argument.
void processArgument(FunctionInfo *info, SILFunctionArgument *argment,
ArgumentSummary &summary, FunctionOrder &order);
/// Summarize a partial_apply instruction.
void processPartialApply(FunctionInfo *callerInfo,
unsigned callerArgumentIndex,
PartialApplyInst *apply,
Operand *applyArgumentOperand, FunctionOrder &order);
/// Summarize apply or try_apply
void processFullApply(FunctionInfo *callerInfo, unsigned callerArgumentIndex,
FullApplySite apply, Operand *argumentOperand,
FunctionOrder &order);
/// Summarize a call site and schedule it for interprocedural analysis.
void processCall(FunctionInfo *callerInfo, unsigned callerArgumentIndex,
SILFunction *calledFunction, unsigned argumentIndex,
FunctionOrder &order);
};
} // end namespace swift
#endif