Skip to content

Commit 4834dcc

Browse files
authored
Merge pull request #10360 from devincoughlin/exclusivity-relax-separate-stored-struct-4.0
[4.0] [Exclusivity] Relax intra-procedural diagnostics on separate stored structs
2 parents 34a4223 + 0303cbf commit 4834dcc

16 files changed

+1535
-177
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,24 +90,24 @@ NOTE(previous_inout_alias,none,
9090
"previous aliasing argument", ())
9191

9292
WARNING(exclusivity_access_required_swift3,none,
93-
"simultaneous accesses to %0 %1, but "
94-
"%select{initialization|read|modification|deinitialization}2 requires "
93+
"overlapping accesses to %0, but "
94+
"%select{initialization|read|modification|deinitialization}1 requires "
9595
"exclusive access; consider copying to a local variable",
96-
(DescriptiveDeclKind, Identifier, unsigned))
96+
(StringRef, unsigned))
9797

9898
ERROR(exclusivity_access_required,none,
99-
"simultaneous accesses to %0 %1, but "
100-
"%select{initialization|read|modification|deinitialization}2 requires "
99+
"overlapping accesses to %0, but "
100+
"%select{initialization|read|modification|deinitialization}1 requires "
101101
"exclusive access; consider copying to a local variable",
102-
(DescriptiveDeclKind, Identifier, unsigned))
102+
(StringRef, unsigned))
103103

104104
ERROR(exclusivity_access_required_unknown_decl,none,
105-
"simultaneous accesses, but "
105+
"overlapping accesses, but "
106106
"%select{initialization|read|modification|deinitialization}0 requires "
107107
"exclusive access; consider copying to a local variable", (unsigned))
108108

109109
WARNING(exclusivity_access_required_unknown_decl_swift3,none,
110-
"simultaneous accesses, but "
110+
"overlapping accesses, but "
111111
"%select{initialization|read|modification|deinitialization}0 requires "
112112
"exclusive access; consider copying to a local variable", (unsigned))
113113

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
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 "swift/SILOptimizer/Utils/IndexTrie.h"
26+
#include "llvm/ADT/DenseMap.h"
27+
#include "llvm/ADT/SmallVector.h"
28+
29+
namespace swift {
30+
31+
class AccessSummaryAnalysis : public BottomUpIPAnalysis {
32+
public:
33+
/// Summarizes the accesses that a function begins on an argument.
34+
class ArgumentSummary {
35+
private:
36+
/// The kind of access begun on the argument.
37+
/// 'None' means no access performed.
38+
Optional<SILAccessKind> Kind = None;
39+
40+
/// The location of the access. Used for diagnostics.
41+
SILLocation AccessLoc = SILLocation((Expr *)nullptr);
42+
43+
public:
44+
Optional<SILAccessKind> getAccessKind() const { return Kind; }
45+
46+
SILLocation getAccessLoc() const { return AccessLoc; }
47+
48+
/// The lattice operation on argument summaries.
49+
bool mergeWith(const ArgumentSummary &other);
50+
51+
/// Merge in an access to the argument of the given kind at the given
52+
/// location. Returns true if the merge caused the summary to change.
53+
bool mergeWith(SILAccessKind otherKind, SILLocation otherLoc);
54+
55+
/// Returns a description of the summary. For debugging and testing
56+
/// purposes.
57+
StringRef getDescription() const;
58+
};
59+
60+
/// Summarizes the accesses that a function begins on its arguments.
61+
class FunctionSummary {
62+
private:
63+
llvm::SmallVector<ArgumentSummary, 6> ArgAccesses;
64+
65+
public:
66+
FunctionSummary(unsigned argCount) : ArgAccesses(argCount) {}
67+
68+
/// Returns of summary of the the function accesses that argument at the
69+
/// given index.
70+
ArgumentSummary &getAccessForArgument(unsigned argument) {
71+
return ArgAccesses[argument];
72+
}
73+
74+
const ArgumentSummary &getAccessForArgument(unsigned argument) const {
75+
return ArgAccesses[argument];
76+
}
77+
78+
/// Returns the number of argument in the summary.
79+
unsigned getArgumentCount() const { return ArgAccesses.size(); }
80+
};
81+
82+
friend raw_ostream &operator<<(raw_ostream &os,
83+
const FunctionSummary &summary);
84+
85+
class FunctionInfo;
86+
/// Records a flow of a caller's argument to a called function.
87+
/// This flow is used to iterate the interprocedural analysis to a fixpoint.
88+
struct ArgumentFlow {
89+
/// The index of the argument in the caller.
90+
const unsigned CallerArgumentIndex;
91+
92+
/// The index of the argument in the callee.
93+
const unsigned CalleeArgumentIndex;
94+
95+
FunctionInfo *const CalleeFunctionInfo;
96+
};
97+
98+
/// Records the summary and argument flows for a given function.
99+
/// Used by the BottomUpIPAnalysis to propagate information
100+
/// from callees to callers.
101+
class FunctionInfo : public FunctionInfoBase<FunctionInfo> {
102+
private:
103+
FunctionSummary FS;
104+
105+
SILFunction *F;
106+
107+
llvm::SmallVector<ArgumentFlow, 8> RecordedArgumentFlows;
108+
109+
public:
110+
FunctionInfo(SILFunction *F) : FS(F->getArguments().size()), F(F) {}
111+
112+
SILFunction *getFunction() const { return F; }
113+
114+
ArrayRef<ArgumentFlow> getArgumentFlows() const {
115+
return RecordedArgumentFlows;
116+
}
117+
118+
const FunctionSummary &getSummary() const { return FS; }
119+
FunctionSummary &getSummary() { return FS; }
120+
121+
/// Record a flow of an argument in this function to a callee.
122+
void recordFlow(const ArgumentFlow &flow) {
123+
flow.CalleeFunctionInfo->addCaller(this, nullptr);
124+
RecordedArgumentFlows.push_back(flow);
125+
}
126+
};
127+
128+
private:
129+
/// Maps functions to the information the analysis keeps for each function.
130+
llvm::DenseMap<SILFunction *, FunctionInfo *> FunctionInfos;
131+
132+
llvm::SpecificBumpPtrAllocator<FunctionInfo> Allocator;
133+
134+
/// A trie of integer indices that gives pointer identity to a path of
135+
/// projections. This is shared between all functions in the module.
136+
IndexTrieNode *SubPathTrie;
137+
138+
public:
139+
AccessSummaryAnalysis() : BottomUpIPAnalysis(AnalysisKind::AccessSummary) {
140+
SubPathTrie = new IndexTrieNode();
141+
}
142+
143+
~AccessSummaryAnalysis() {
144+
delete SubPathTrie;
145+
}
146+
147+
/// Returns a summary of the accesses performed by the given function.
148+
const FunctionSummary &getOrCreateSummary(SILFunction *Fn);
149+
150+
IndexTrieNode *getSubPathTrieRoot() {
151+
return SubPathTrie;
152+
}
153+
154+
virtual void initialize(SILPassManager *PM) override {}
155+
virtual void invalidate() override;
156+
virtual void invalidate(SILFunction *F, InvalidationKind K) override;
157+
virtual void notifyAddFunction(SILFunction *F) override {}
158+
virtual void notifyDeleteFunction(SILFunction *F) override {
159+
invalidate(F, InvalidationKind::Nothing);
160+
}
161+
virtual void invalidateFunctionTables() override {}
162+
163+
static bool classof(const SILAnalysis *S) {
164+
return S->getKind() == AnalysisKind::AccessSummary;
165+
}
166+
167+
private:
168+
typedef BottomUpFunctionOrder<FunctionInfo> FunctionOrder;
169+
170+
/// Returns the BottomUpIPAnalysis information for the given function.
171+
FunctionInfo *getFunctionInfo(SILFunction *F);
172+
173+
/// Summarizes the given function and iterates the interprocedural analysis
174+
/// to a fixpoint.
175+
void recompute(FunctionInfo *initial);
176+
177+
/// Propagate the access summary from the argument of a called function
178+
/// to the caller.
179+
bool propagateFromCalleeToCaller(FunctionInfo *callerInfo,
180+
ArgumentFlow site);
181+
182+
/// Summarize the given function and schedule it for interprocedural
183+
/// analysis.
184+
void processFunction(FunctionInfo *info, FunctionOrder &order);
185+
186+
/// Summarize how the function uses the given argument.
187+
void processArgument(FunctionInfo *info, SILFunctionArgument *argment,
188+
ArgumentSummary &summary, FunctionOrder &order);
189+
190+
/// Summarize a partial_apply instruction.
191+
void processPartialApply(FunctionInfo *callerInfo,
192+
unsigned callerArgumentIndex,
193+
PartialApplyInst *apply,
194+
Operand *applyArgumentOperand, FunctionOrder &order);
195+
196+
/// Summarize apply or try_apply
197+
void processFullApply(FunctionInfo *callerInfo, unsigned callerArgumentIndex,
198+
FullApplySite apply, Operand *argumentOperand,
199+
FunctionOrder &order);
200+
201+
/// Summarize a call site and schedule it for interprocedural analysis.
202+
void processCall(FunctionInfo *callerInfo, unsigned callerArgumentIndex,
203+
SILFunction *calledFunction, unsigned argumentIndex,
204+
FunctionOrder &order);
205+
};
206+
207+
} // end namespace swift
208+
209+
#endif
210+

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",
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//===--- IndexTrie - Trie for a sequence of integer indices ----*- 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+
#ifndef SWIFT_SILOPTIMIZER_UTILS_INDEXTREE_H
14+
#define SWIFT_SILOPTIMIZER_UTILS_INDEXTREE_H
15+
16+
#include "llvm/ADT/ArrayRef.h"
17+
#include "llvm/ADT/SmallVector.h"
18+
#include <algorithm>
19+
20+
namespace swift {
21+
22+
// Trie node representing a sequence of unsigned integer indices.
23+
class IndexTrieNode {
24+
static const unsigned RootIdx = ~0U;
25+
unsigned Index;
26+
llvm::SmallVector<IndexTrieNode*, 8> Children;
27+
IndexTrieNode *Parent;
28+
29+
public:
30+
IndexTrieNode(): Index(RootIdx), Parent(nullptr) {}
31+
32+
explicit IndexTrieNode(unsigned V, IndexTrieNode *P): Index(V), Parent(P) {}
33+
34+
IndexTrieNode(IndexTrieNode &) =delete;
35+
IndexTrieNode &operator=(const IndexTrieNode&) =delete;
36+
37+
~IndexTrieNode() {
38+
for (auto *N : Children)
39+
delete N;
40+
}
41+
42+
bool isRoot() const { return Index == RootIdx; }
43+
44+
bool isLeaf() const { return Children.empty(); }
45+
46+
unsigned getIndex() const { return Index; }
47+
48+
IndexTrieNode *getChild(unsigned Idx) {
49+
assert(Idx != RootIdx);
50+
51+
auto I = std::lower_bound(Children.begin(), Children.end(), Idx,
52+
[](IndexTrieNode *a, unsigned i) {
53+
return a->Index < i;
54+
});
55+
if (I != Children.end() && (*I)->Index == Idx)
56+
return *I;
57+
auto *N = new IndexTrieNode(Idx, this);
58+
Children.insert(I, N);
59+
return N;
60+
}
61+
62+
ArrayRef<IndexTrieNode*> getChildren() const { return Children; }
63+
64+
IndexTrieNode *getParent() const { return Parent; }
65+
66+
/// Returns true when the sequence of indices represented by this
67+
/// node is a prefix of the sequence represented by the passed-in node.
68+
bool isPrefixOf(const IndexTrieNode *Other) const {
69+
const IndexTrieNode *I = Other;
70+
71+
do {
72+
if (this == I)
73+
return true;
74+
75+
I = I->getParent();
76+
} while (I);
77+
78+
return false;
79+
}
80+
};
81+
82+
} // end namespace swift
83+
84+
#endif

0 commit comments

Comments
 (0)