Skip to content

Commit cb17cfc

Browse files
committed
[Exclusivity] Add analysis pass summarizing accesses to inout_aliasable args
Add an interprocedural SIL analysis pass that summarizes the accesses that closures make on their @inout_aliasable captures. This will be used to statically enforce exclusivity for calls to functions that take noescape closures. The analysis summarizes the accesses on each argument independently and uses the BottomUpIPAnalysis utility class to iterate to a fixed point when there are cycles in the call graph. For now, the analysis is not stored-property-sensitive -- that will come in a later commit.
1 parent 9d67d6c commit cb17cfc

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)