Skip to content

Commit 32082f6

Browse files
authored
Merge pull request #10191 from devincoughlin/noescape-closure-access-summary
2 parents 0a43288 + d2ac3d5 commit 32082f6

File tree

8 files changed

+873
-0
lines changed

8 files changed

+873
-0
lines changed
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
//===--- AccessSummaryAnalysis.h - SIL Access Summary Analysis --*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file implements an interprocedural analysis pass that summarizes
14+
// the formal accesses that a function makes to its address-type arguments.
15+
// These summaries are used to statically diagnose violations of exclusive
16+
// accesses for noescape closures.
17+
//
18+
//===----------------------------------------------------------------------===//
19+
#ifndef SWIFT_SILOPTIMIZER_ANALYSIS_ACCESS_SUMMARY_ANALYSIS_H_
20+
#define SWIFT_SILOPTIMIZER_ANALYSIS_ACCESS_SUMMARY_ANALYSIS_H_
21+
22+
#include "swift/SIL/SILFunction.h"
23+
#include "swift/SIL/SILInstruction.h"
24+
#include "swift/SILOptimizer/Analysis/BottomUpIPAnalysis.h"
25+
#include "llvm/ADT/DenseMap.h"
26+
#include "llvm/ADT/SmallVector.h"
27+
28+
namespace swift {
29+
30+
class AccessSummaryAnalysis : public BottomUpIPAnalysis {
31+
public:
32+
/// Summarizes the accesses that a function begins on an argument.
33+
class ArgumentSummary {
34+
private:
35+
/// The kind of access begun on the argument.
36+
/// 'None' means no access performed.
37+
Optional<SILAccessKind> Kind = None;
38+
39+
/// The location of the access. Used for diagnostics.
40+
SILLocation AccessLoc = SILLocation((Expr *)nullptr);
41+
42+
public:
43+
Optional<SILAccessKind> getAccessKind() const { return Kind; }
44+
45+
SILLocation getAccessLoc() const { return AccessLoc; }
46+
47+
/// The lattice operation on argument summaries.
48+
bool mergeWith(const ArgumentSummary &other);
49+
50+
/// Merge in an access to the argument of the given kind at the given
51+
/// location. Returns true if the merge caused the summary to change.
52+
bool mergeWith(SILAccessKind otherKind, SILLocation otherLoc);
53+
54+
/// Returns a description of the summary. For debugging and testing
55+
/// purposes.
56+
StringRef getDescription() const;
57+
};
58+
59+
/// Summarizes the accesses that a function begins on its arguments.
60+
class FunctionSummary {
61+
private:
62+
llvm::SmallVector<ArgumentSummary, 6> ArgAccesses;
63+
64+
public:
65+
FunctionSummary(unsigned argCount) : ArgAccesses(argCount) {}
66+
67+
/// Returns of summary of the the function accesses that argument at the
68+
/// given index.
69+
ArgumentSummary &getAccessForArgument(unsigned argument) {
70+
return ArgAccesses[argument];
71+
}
72+
73+
const ArgumentSummary &getAccessForArgument(unsigned argument) const {
74+
return ArgAccesses[argument];
75+
}
76+
77+
/// Returns the number of argument in the summary.
78+
unsigned getArgumentCount() const { return ArgAccesses.size(); }
79+
};
80+
81+
friend raw_ostream &operator<<(raw_ostream &os,
82+
const FunctionSummary &summary);
83+
84+
class FunctionInfo;
85+
/// Records a flow of a caller's argument to a called function.
86+
/// This flow is used to iterate the interprocedural analysis to a fixpoint.
87+
struct ArgumentFlow {
88+
/// The index of the argument in the caller.
89+
const unsigned CallerArgumentIndex;
90+
91+
/// The index of the argument in the callee.
92+
const unsigned CalleeArgumentIndex;
93+
94+
FunctionInfo *const CalleeFunctionInfo;
95+
};
96+
97+
/// Records the summary and argument flows for a given function.
98+
/// Used by the BottomUpIPAnalysis to propagate information
99+
/// from callees to callers.
100+
class FunctionInfo : public FunctionInfoBase<FunctionInfo> {
101+
private:
102+
FunctionSummary FS;
103+
104+
SILFunction *F;
105+
106+
llvm::SmallVector<ArgumentFlow, 8> RecordedArgumentFlows;
107+
108+
public:
109+
FunctionInfo(SILFunction *F) : FS(F->getArguments().size()), F(F) {}
110+
111+
SILFunction *getFunction() const { return F; }
112+
113+
ArrayRef<ArgumentFlow> getArgumentFlows() const {
114+
return RecordedArgumentFlows;
115+
}
116+
117+
const FunctionSummary &getSummary() const { return FS; }
118+
FunctionSummary &getSummary() { return FS; }
119+
120+
/// Record a flow of an argument in this function to a callee.
121+
void recordFlow(const ArgumentFlow &flow) {
122+
flow.CalleeFunctionInfo->addCaller(this, nullptr);
123+
RecordedArgumentFlows.push_back(flow);
124+
}
125+
};
126+
127+
private:
128+
/// Maps functions to the information the analysis keeps for each function.
129+
llvm::DenseMap<SILFunction *, FunctionInfo *> FunctionInfos;
130+
131+
llvm::SpecificBumpPtrAllocator<FunctionInfo> Allocator;
132+
public:
133+
AccessSummaryAnalysis() : BottomUpIPAnalysis(AnalysisKind::AccessSummary) {}
134+
135+
/// Returns a summary of the accesses performed by the given function.
136+
const FunctionSummary &getOrCreateSummary(SILFunction *Fn);
137+
138+
virtual void initialize(SILPassManager *PM) override {}
139+
virtual void invalidate() override;
140+
virtual void invalidate(SILFunction *F, InvalidationKind K) override;
141+
virtual void notifyAddFunction(SILFunction *F) override {}
142+
virtual void notifyDeleteFunction(SILFunction *F) override {
143+
invalidate(F, InvalidationKind::Nothing);
144+
}
145+
virtual void invalidateFunctionTables() override {}
146+
147+
static bool classof(const SILAnalysis *S) {
148+
return S->getKind() == AnalysisKind::AccessSummary;
149+
}
150+
151+
private:
152+
typedef BottomUpFunctionOrder<FunctionInfo> FunctionOrder;
153+
154+
/// Returns the BottomUpIPAnalysis information for the given function.
155+
FunctionInfo *getFunctionInfo(SILFunction *F);
156+
157+
/// Summarizes the given function and iterates the interprocedural analysis
158+
/// to a fixpoint.
159+
void recompute(FunctionInfo *initial);
160+
161+
/// Propagate the access summary from the argument of a called function
162+
/// to the caller.
163+
bool propagateFromCalleeToCaller(FunctionInfo *callerInfo,
164+
ArgumentFlow site);
165+
166+
/// Summarize the given function and schedule it for interprocedural
167+
/// analysis.
168+
void processFunction(FunctionInfo *info, FunctionOrder &order);
169+
170+
/// Summarize how the function uses the given argument.
171+
void processArgument(FunctionInfo *info, SILFunctionArgument *argment,
172+
ArgumentSummary &summary, FunctionOrder &order);
173+
174+
/// Summarize a partial_apply instruction.
175+
void processPartialApply(FunctionInfo *callerInfo,
176+
unsigned callerArgumentIndex,
177+
PartialApplyInst *apply,
178+
Operand *applyArgumentOperand, FunctionOrder &order);
179+
180+
/// Summarize apply or try_apply
181+
void processFullApply(FunctionInfo *callerInfo, unsigned callerArgumentIndex,
182+
FullApplySite apply, Operand *argumentOperand,
183+
FunctionOrder &order);
184+
185+
/// Summarize a call site and schedule it for interprocedural analysis.
186+
void processCall(FunctionInfo *callerInfo, unsigned callerArgumentIndex,
187+
SILFunction *calledFunction, unsigned argumentIndex,
188+
FunctionOrder &order);
189+
};
190+
191+
} // end namespace swift
192+
193+
#endif
194+

include/swift/SILOptimizer/Analysis/Analysis.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#define ANALYSIS(NAME)
2424
#endif
2525

26+
ANALYSIS(AccessSummary)
2627
ANALYSIS(Alias)
2728
ANALYSIS(BasicCallee)
2829
ANALYSIS(Caller)

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ PASS(ABCOpt, "abcopts",
5656
"Array Bounds Check Optimization")
5757
PASS(AccessEnforcementSelection, "access-enforcement-selection",
5858
"Access Enforcement Selection")
59+
PASS(AccessSummaryDumper, "access-summary-dump",
60+
"Dump Address Parameter Access Summary")
5961
PASS(InactiveAccessMarkerElimination, "inactive-access-marker-elim",
6062
"Inactive Access Marker Elimination.")
6163
PASS(FullAccessMarkerElimination, "full-access-marker-elim",

0 commit comments

Comments
 (0)