Skip to content

Commit

Permalink
[Exclusivity] Relax closure enforcement on separate stored properties (
Browse files Browse the repository at this point in the history
…swiftlang#10789)

Make the static enforcement of accesses in noescape closures stored-property
sensitive. This will relax the existing enforcement so that the following is
not diagnosed:

struct MyStruct {
   var x = X()
   var y = Y()

  mutating
  func foo() {
    x.mutatesAndTakesClosure() {
      _ = y.read() // no-warning
   }
  }
}

To do this, update the access summary analysis to summarize accesses to
subpaths of a capture.

rdar://problem/32987932
  • Loading branch information
devincoughlin authored Jul 10, 2017
1 parent 1bcca77 commit 47d9de9
Show file tree
Hide file tree
Showing 6 changed files with 544 additions and 172 deletions.
77 changes: 66 additions & 11 deletions include/swift/SILOptimizer/Analysis/AccessSummaryAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,34 +30,75 @@ namespace swift {

class AccessSummaryAnalysis : public BottomUpIPAnalysis {
public:
/// Summarizes the accesses that a function begins on an argument.
class ArgumentSummary {
class SubAccessSummary {
private:
/// The kind of access begun on the argument.
/// 'None' means no access performed.
Optional<SILAccessKind> Kind = None;
SILAccessKind Kind;

/// The location of the access. Used for diagnostics.
SILLocation AccessLoc = SILLocation((Expr *)nullptr);

const IndexTrieNode *SubPath = nullptr;

public:
Optional<SILAccessKind> getAccessKind() const { return Kind; }
SubAccessSummary(SILAccessKind Kind, SILLocation AccessLoc,
const IndexTrieNode *SubPath)
: Kind(Kind), AccessLoc(AccessLoc), SubPath(SubPath) {}

SILAccessKind getAccessKind() const { return Kind; }

SILLocation getAccessLoc() const { return AccessLoc; }

const IndexTrieNode *getSubPath() const { return SubPath; }

/// The lattice operation on SubAccessSummaries summaries.
bool mergeWith(const SubAccessSummary &other);

/// Merge in an access to the argument of the given kind at the given
/// location with the given suppath. Returns true if the merge caused the
/// summary to change.
bool mergeWith(SILAccessKind otherKind, SILLocation otherLoc,
const IndexTrieNode *otherSubPath);

/// Returns a description of the summary. For debugging and testing
/// purposes.
std::string getDescription(SILType BaseType, SILModule &M) const;
};

typedef llvm::SmallDenseMap<const IndexTrieNode *, SubAccessSummary, 8>
SubAccessMap;

/// Summarizes the accesses that a function begins on an argument, including
/// the projection subpath that was accessed.
class ArgumentSummary {
private:
SubAccessMap SubAccesses;

public:
/// The lattice operation on argument summaries.
bool mergeWith(const ArgumentSummary &other);

/// Merge in an access to the argument of the given kind at the given
/// location. Returns true if the merge caused the summary to change.
bool mergeWith(SILAccessKind otherKind, SILLocation otherLoc);
bool mergeWith(SILAccessKind otherKind, SILLocation otherLoc,
const IndexTrieNode *otherSubPath);

/// Returns a description of the summary. For debugging and testing
/// purposes.
StringRef getDescription() const;
std::string getDescription(SILType BaseType, SILModule &M) const;

/// Returns the accesses that the function performs to subpaths of the
/// argument.
const SubAccessMap &getSubAccesses() const { return SubAccesses; }

/// Returns the sorted subaccess summaries into the passed-in storage.
/// The accesses are sorted lexicographically by increasing subpath
/// length and projection index.
void getSortedSubAccesses(SmallVectorImpl<SubAccessSummary> &storage) const;
};

/// Summarizes the accesses that a function begins on its arguments.
/// Summarizes the accesses that a function begins on its arguments or
/// projections from its arguments.
class FunctionSummary {
private:
llvm::SmallVector<ArgumentSummary, 6> ArgAccesses;
Expand All @@ -77,10 +118,9 @@ class AccessSummaryAnalysis : public BottomUpIPAnalysis {

/// Returns the number of argument in the summary.
unsigned getArgumentCount() const { return ArgAccesses.size(); }
};

friend raw_ostream &operator<<(raw_ostream &os,
const FunctionSummary &summary);
void print(raw_ostream &os, SILFunction *fn) const;
};

class FunctionInfo;
/// Records a flow of a caller's argument to a called function.
Expand Down Expand Up @@ -151,6 +191,10 @@ class AccessSummaryAnalysis : public BottomUpIPAnalysis {
return SubPathTrie;
}

/// Returns an IndexTrieNode that represents the single subpath accessed from
/// BAI or the root if no such node exists.
const IndexTrieNode *findSubPathAccessed(BeginAccessInst *BAI);

virtual void initialize(SILPassManager *PM) override {}
virtual void invalidate() override;
virtual void invalidate(SILFunction *F, InvalidationKind K) override;
Expand All @@ -164,6 +208,17 @@ class AccessSummaryAnalysis : public BottomUpIPAnalysis {
return S->getKind() == AnalysisKind::AccessSummary;
}

/// Returns a description of the subpath suitable for use in diagnostics.
/// The base type must be the type of the root of the path.
static std::string getSubPathDescription(SILType BaseType,
const IndexTrieNode *SubPath,
SILModule &M);

/// Performs a lexicographic comparison of two subpaths, first by path length
/// and then by index of the last path component. Returns true when lhs
/// is less than rhs.
static bool compareSubPaths(const IndexTrieNode *lhs,
const IndexTrieNode *rhs);
private:
typedef BottomUpFunctionOrder<FunctionInfo> FunctionOrder;

Expand Down
Loading

0 comments on commit 47d9de9

Please sign in to comment.