Skip to content

Cleanup/fix AccessEnforcementOpts #23190

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Mar 20, 2019
143 changes: 114 additions & 29 deletions include/swift/SILOptimizer/Analysis/AccessedStorageAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ template <> struct DenseMapInfo<swift::StorageAccessInfo> {
}

namespace swift {
/// The per-function result of AccessedStorageAnalysis.
///
using AccessedStorageSet = llvm::SmallDenseSet<StorageAccessInfo, 8>;

/// Records each unique AccessedStorage in a set of StorageAccessInfo
/// objects. Hashing and equality only sees the AccesedStorage data. The
/// additional StorageAccessInfo bits are recorded as results of this analysis.
Expand All @@ -133,28 +133,32 @@ namespace swift {
/// results, either because the call graph is unknown or the access sets are too
/// large. It does not imply that all accesses have Unidentified
/// AccessedStorage, which is never allowed for class or global access.
class FunctionAccessedStorage {
using AccessedStorageSet = llvm::SmallDenseSet<StorageAccessInfo, 8>;

class AccessedStorageResult {
AccessedStorageSet storageAccessSet;
Optional<SILAccessKind> unidentifiedAccess;

public:
FunctionAccessedStorage() {}
AccessedStorageResult() {}

// ---------------------------------------------------------------------------
// Accessing the results.

const AccessedStorageSet &getStorageSet() const { return storageAccessSet; }

bool isEmpty() const {
return storageAccessSet.empty() && !unidentifiedAccess;
}

bool hasUnidentifiedAccess() const { return unidentifiedAccess != None; }

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

/// Does any of the accesses represented by this FunctionAccessedStorage
/// Does any of the accesses represented by this AccessedStorageResult
/// object conflict with the given access kind and storage.
bool mayConflictWith(SILAccessKind otherAccessKind,
const AccessedStorage &otherStorage) const;
Expand All @@ -181,6 +185,97 @@ class FunctionAccessedStorage {
unidentifiedAccess = SILAccessKind::Modify;
}

void setUnidentifiedAccess(SILAccessKind kind) { unidentifiedAccess = kind; }

/// Merge effects directly from \p RHS.
bool mergeFrom(const AccessedStorageResult &other);

/// Merge the effects represented in calleeAccess into this
/// FunctionAccessedStorage object. calleeAccess must correspond to at least
/// one callee at the apply site `fullApply`. Merging drops any local effects,
/// and translates parameter effects into effects on the caller-side
/// arguments.
///
/// The full caller-side effects at a call site can be obtained with
/// AccessedStorageAnalysis::getCallSiteEffects().
bool mergeFromApply(const AccessedStorageResult &calleeAccess,
FullApplySite fullApply);

/// Record any access scopes entered by the given single SIL instruction. 'I'
/// must not be a FullApply; use mergeFromApply instead.
void analyzeInstruction(SILInstruction *I);

void print(raw_ostream &os) const;
void dump() const;

protected:
std::pair<AccessedStorageSet::iterator, bool>
insertStorageAccess(StorageAccessInfo storageAccess) {
storageAccess.setStorageIndex(storageAccessSet.size());
return storageAccessSet.insert(storageAccess);
}

bool updateUnidentifiedAccess(SILAccessKind accessKind);

bool mergeAccesses(const AccessedStorageResult &other,
std::function<StorageAccessInfo(const StorageAccessInfo &)>
transformStorage);

template <typename B> void visitBeginAccess(B *beginAccess);
};
} // namespace swift

namespace swift {
/// The per-function result of AccessedStorageAnalysis.
class FunctionAccessedStorage {
AccessedStorageResult accessResult;

public:
FunctionAccessedStorage() {}

// ---------------------------------------------------------------------------
// Accessing the results.

const AccessedStorageResult &getResult() const { return accessResult; }

bool hasUnidentifiedAccess() const {
return accessResult.hasUnidentifiedAccess();
}

/// Return true if the analysis has determined all accesses of otherStorage
/// have the [no_nested_conflict] flag set.
///
/// Only call this if there is no unidentifiedAccess in the function and the
/// given storage is uniquely identified.
bool hasNoNestedConflict(const AccessedStorage &otherStorage) const {
return accessResult.hasNoNestedConflict(otherStorage);
}

/// Does any of the accesses represented by this FunctionAccessedStorage
/// object conflict with the given access kind and storage.
bool mayConflictWith(SILAccessKind otherAccessKind,
const AccessedStorage &otherStorage) const {
return accessResult.mayConflictWith(otherAccessKind, otherStorage);
}

/// Raw access to the result for a given AccessedStorage location.
StorageAccessInfo
getStorageAccessInfo(const AccessedStorage &otherStorage) const {
return accessResult.getStorageAccessInfo(otherStorage);
}

// ---------------------------------------------------------------------------
// Constructing the results.

void clear() { accessResult.clear(); }

/// Return true if these effects are fully conservative.
bool hasWorstEffects() { return accessResult.hasWorstEffects(); }

/// Sets the most conservative effects, if we don't know anything about the
/// function.
void setWorstEffects() { accessResult.setWorstEffects(); }

/// Summarize the given function's effects using this FunctionAccessedStorage
/// object.
//
Expand All @@ -201,12 +296,14 @@ class FunctionAccessedStorage {
///
/// TODO: Summarize ArraySemanticsCall accesses.
bool summarizeCall(FullApplySite fullApply) {
assert(storageAccessSet.empty() && "expected uninitialized results.");
assert(accessResult.isEmpty() && "expected uninitialized results.");
return false;
}

/// Merge effects directly from \p RHS.
bool mergeFrom(const FunctionAccessedStorage &RHS);
bool mergeFrom(const FunctionAccessedStorage &RHS) {
return accessResult.mergeFrom(RHS.accessResult);
}

/// Merge the effects represented in calleeAccess into this
/// FunctionAccessedStorage object. calleeAccess must correspond to at least
Expand All @@ -217,31 +314,19 @@ class FunctionAccessedStorage {
/// The full caller-side effects at a call site can be obtained with
/// AccessedStorageAnalysis::getCallSiteEffects().
bool mergeFromApply(const FunctionAccessedStorage &calleeAccess,
FullApplySite fullApply);
FullApplySite fullApply) {
return accessResult.mergeFromApply(calleeAccess.accessResult, fullApply);
}

/// Analyze the side-effects of a single SIL instruction \p I.
/// Visited callees are added to \p BottomUpOrder until \p RecursionDepth
/// reaches MaxRecursionDepth.
void analyzeInstruction(SILInstruction *I);

void print(raw_ostream &os) const;
void dump() const;

protected:
std::pair<AccessedStorageSet::iterator, bool>
insertStorageAccess(StorageAccessInfo storageAccess) {
storageAccess.setStorageIndex(storageAccessSet.size());
return storageAccessSet.insert(storageAccess);
void analyzeInstruction(SILInstruction *I) {
accessResult.analyzeInstruction(I);
}

bool updateUnidentifiedAccess(SILAccessKind accessKind);

bool mergeAccesses(
const FunctionAccessedStorage &other,
std::function<StorageAccessInfo(const StorageAccessInfo &)>
transformStorage);

template <typename B> void visitBeginAccess(B *beginAccess);
void print(raw_ostream &os) const { accessResult.print(os); }
void dump() const { accessResult.dump(); }
};

/// Summarizes the dynamic accesses performed within a function and its
Expand Down
Loading