Skip to content

Commit 72a9190

Browse files
committed
Expose AccessedStorageAnalysis as a utility.
The previous design was customized to perfoming IPO with GenericSideEffectAnalysis. Expose the underlying logic as a utility so that AccessEnforcementOpts can use it to summarize loops (in addition to call sites).
1 parent d882b09 commit 72a9190

File tree

2 files changed

+173
-84
lines changed

2 files changed

+173
-84
lines changed

include/swift/SILOptimizer/Analysis/AccessedStorageAnalysis.h

Lines changed: 111 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,6 @@ template <> struct DenseMapInfo<swift::StorageAccessInfo> {
122122
}
123123

124124
namespace swift {
125-
/// The per-function result of AccessedStorageAnalysis.
126-
///
127125
/// Records each unique AccessedStorage in a set of StorageAccessInfo
128126
/// objects. Hashing and equality only sees the AccesedStorage data. The
129127
/// additional StorageAccessInfo bits are recorded as results of this analysis.
@@ -133,28 +131,32 @@ namespace swift {
133131
/// results, either because the call graph is unknown or the access sets are too
134132
/// large. It does not imply that all accesses have Unidentified
135133
/// AccessedStorage, which is never allowed for class or global access.
136-
class FunctionAccessedStorage {
134+
class AccessedStorageResult {
135+
137136
using AccessedStorageSet = llvm::SmallDenseSet<StorageAccessInfo, 8>;
138137

139138
AccessedStorageSet storageAccessSet;
140139
Optional<SILAccessKind> unidentifiedAccess;
141-
142140
public:
143-
FunctionAccessedStorage() {}
141+
AccessedStorageResult() {}
144142

145143
// ---------------------------------------------------------------------------
146144
// Accessing the results.
147145

146+
bool isEmpty() const {
147+
return storageAccessSet.empty() && !unidentifiedAccess;
148+
}
149+
148150
bool hasUnidentifiedAccess() const { return unidentifiedAccess != None; }
149151

150152
/// Return true if the analysis has determined all accesses of otherStorage
151153
/// have the [no_nested_conflict] flag set.
152154
///
153-
/// Only call this if there is no unidentifiedAccess in the function and the
155+
/// Only call this if there is no unidentifiedAccess in the region and the
154156
/// given storage is uniquely identified.
155157
bool hasNoNestedConflict(const AccessedStorage &otherStorage) const;
156158

157-
/// Does any of the accesses represented by this FunctionAccessedStorage
159+
/// Does any of the accesses represented by this AccessedStorageResult
158160
/// object conflict with the given access kind and storage.
159161
bool mayConflictWith(SILAccessKind otherAccessKind,
160162
const AccessedStorage &otherStorage) const;
@@ -181,6 +183,97 @@ class FunctionAccessedStorage {
181183
unidentifiedAccess = SILAccessKind::Modify;
182184
}
183185

186+
void setUnidentifiedAccess(SILAccessKind kind) { unidentifiedAccess = kind; }
187+
188+
/// Merge effects directly from \p RHS.
189+
bool mergeFrom(const AccessedStorageResult &other);
190+
191+
/// Merge the effects represented in calleeAccess into this
192+
/// FunctionAccessedStorage object. calleeAccess must correspond to at least
193+
/// one callee at the apply site `fullApply`. Merging drops any local effects,
194+
/// and translates parameter effects into effects on the caller-side
195+
/// arguments.
196+
///
197+
/// The full caller-side effects at a call site can be obtained with
198+
/// AccessedStorageAnalysis::getCallSiteEffects().
199+
bool mergeFromApply(const AccessedStorageResult &calleeAccess,
200+
FullApplySite fullApply);
201+
202+
/// Record any access scopes entered by the given single SIL instruction. 'I'
203+
/// must not be a FullApply; use mergeFromApply instead.
204+
void analyzeInstruction(SILInstruction *I);
205+
206+
void print(raw_ostream &os) const;
207+
void dump() const;
208+
209+
protected:
210+
std::pair<AccessedStorageSet::iterator, bool>
211+
insertStorageAccess(StorageAccessInfo storageAccess) {
212+
storageAccess.setStorageIndex(storageAccessSet.size());
213+
return storageAccessSet.insert(storageAccess);
214+
}
215+
216+
bool updateUnidentifiedAccess(SILAccessKind accessKind);
217+
218+
bool mergeAccesses(const AccessedStorageResult &other,
219+
std::function<StorageAccessInfo(const StorageAccessInfo &)>
220+
transformStorage);
221+
222+
template <typename B> void visitBeginAccess(B *beginAccess);
223+
};
224+
} // namespace swift
225+
226+
namespace swift {
227+
/// The per-function result of AccessedStorageAnalysis.
228+
class FunctionAccessedStorage {
229+
AccessedStorageResult accessResult;
230+
231+
public:
232+
FunctionAccessedStorage() {}
233+
234+
// ---------------------------------------------------------------------------
235+
// Accessing the results.
236+
237+
const AccessedStorageResult &getResult() const { return accessResult; }
238+
239+
bool hasUnidentifiedAccess() const {
240+
return accessResult.hasUnidentifiedAccess();
241+
}
242+
243+
/// Return true if the analysis has determined all accesses of otherStorage
244+
/// have the [no_nested_conflict] flag set.
245+
///
246+
/// Only call this if there is no unidentifiedAccess in the function and the
247+
/// given storage is uniquely identified.
248+
bool hasNoNestedConflict(const AccessedStorage &otherStorage) const {
249+
return accessResult.hasNoNestedConflict(otherStorage);
250+
}
251+
252+
/// Does any of the accesses represented by this FunctionAccessedStorage
253+
/// object conflict with the given access kind and storage.
254+
bool mayConflictWith(SILAccessKind otherAccessKind,
255+
const AccessedStorage &otherStorage) const {
256+
return accessResult.mayConflictWith(otherAccessKind, otherStorage);
257+
}
258+
259+
/// Raw access to the result for a given AccessedStorage location.
260+
StorageAccessInfo
261+
getStorageAccessInfo(const AccessedStorage &otherStorage) const {
262+
return accessResult.getStorageAccessInfo(otherStorage);
263+
}
264+
265+
// ---------------------------------------------------------------------------
266+
// Constructing the results.
267+
268+
void clear() { accessResult.clear(); }
269+
270+
/// Return true if these effects are fully conservative.
271+
bool hasWorstEffects() { return accessResult.hasWorstEffects(); }
272+
273+
/// Sets the most conservative effects, if we don't know anything about the
274+
/// function.
275+
void setWorstEffects() { accessResult.setWorstEffects(); }
276+
184277
/// Summarize the given function's effects using this FunctionAccessedStorage
185278
/// object.
186279
//
@@ -201,12 +294,14 @@ class FunctionAccessedStorage {
201294
///
202295
/// TODO: Summarize ArraySemanticsCall accesses.
203296
bool summarizeCall(FullApplySite fullApply) {
204-
assert(storageAccessSet.empty() && "expected uninitialized results.");
297+
assert(accessResult.isEmpty() && "expected uninitialized results.");
205298
return false;
206299
}
207300

208301
/// Merge effects directly from \p RHS.
209-
bool mergeFrom(const FunctionAccessedStorage &RHS);
302+
bool mergeFrom(const FunctionAccessedStorage &RHS) {
303+
return accessResult.mergeFrom(RHS.accessResult);
304+
}
210305

211306
/// Merge the effects represented in calleeAccess into this
212307
/// FunctionAccessedStorage object. calleeAccess must correspond to at least
@@ -217,31 +312,19 @@ class FunctionAccessedStorage {
217312
/// The full caller-side effects at a call site can be obtained with
218313
/// AccessedStorageAnalysis::getCallSiteEffects().
219314
bool mergeFromApply(const FunctionAccessedStorage &calleeAccess,
220-
FullApplySite fullApply);
315+
FullApplySite fullApply) {
316+
return accessResult.mergeFromApply(calleeAccess.accessResult, fullApply);
317+
}
221318

222319
/// Analyze the side-effects of a single SIL instruction \p I.
223320
/// Visited callees are added to \p BottomUpOrder until \p RecursionDepth
224321
/// reaches MaxRecursionDepth.
225-
void analyzeInstruction(SILInstruction *I);
226-
227-
void print(raw_ostream &os) const;
228-
void dump() const;
229-
230-
protected:
231-
std::pair<AccessedStorageSet::iterator, bool>
232-
insertStorageAccess(StorageAccessInfo storageAccess) {
233-
storageAccess.setStorageIndex(storageAccessSet.size());
234-
return storageAccessSet.insert(storageAccess);
322+
void analyzeInstruction(SILInstruction *I) {
323+
accessResult.analyzeInstruction(I);
235324
}
236325

237-
bool updateUnidentifiedAccess(SILAccessKind accessKind);
238-
239-
bool mergeAccesses(
240-
const FunctionAccessedStorage &other,
241-
std::function<StorageAccessInfo(const StorageAccessInfo &)>
242-
transformStorage);
243-
244-
template <typename B> void visitBeginAccess(B *beginAccess);
326+
void print(raw_ostream &os) const { accessResult.print(os); }
327+
void dump() const { accessResult.dump(); }
245328
};
246329

247330
/// Summarizes the dynamic accesses performed within a function and its

0 commit comments

Comments
 (0)