Skip to content

Commit

Permalink
Merge pull request #34126 from atrick/add-accesspath
Browse files Browse the repository at this point in the history
Add an AccessPath abstraction and formalize memory access
  • Loading branch information
atrick authored Oct 19, 2020
2 parents 68b790f + 5e0c8f9 commit fd8f723
Show file tree
Hide file tree
Showing 43 changed files with 4,034 additions and 645 deletions.
462 changes: 462 additions & 0 deletions docs/SILProgrammersManual.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#ifndef SWIFT_SILOPTIMIZER_UTILS_INDEXTREE_H
#define SWIFT_SILOPTIMIZER_UTILS_INDEXTREE_H

#include "swift/Basic/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include <algorithm>
Expand All @@ -21,15 +22,18 @@ namespace swift {

// Trie node representing a sequence of unsigned integer indices.
class IndexTrieNode {
static const unsigned RootIdx = ~0U;
unsigned Index;
public:
static const int RootIndex = std::numeric_limits<int>::min();

private:
int Index;
llvm::SmallVector<IndexTrieNode*, 8> Children;
IndexTrieNode *Parent;

public:
IndexTrieNode(): Index(RootIdx), Parent(nullptr) {}
IndexTrieNode() : Index(RootIndex), Parent(nullptr) {}

explicit IndexTrieNode(unsigned V, IndexTrieNode *P): Index(V), Parent(P) {}
explicit IndexTrieNode(int V, IndexTrieNode *P) : Index(V), Parent(P) {}

IndexTrieNode(IndexTrieNode &) =delete;
IndexTrieNode &operator=(const IndexTrieNode&) =delete;
Expand All @@ -39,19 +43,18 @@ class IndexTrieNode {
delete N;
}

bool isRoot() const { return Index == RootIdx; }
bool isRoot() const { return Index == RootIndex; }

bool isLeaf() const { return Children.empty(); }

unsigned getIndex() const { return Index; }
int getIndex() const { return Index; }

IndexTrieNode *getChild(unsigned Idx) {
assert(Idx != RootIdx);
IndexTrieNode *getChild(int Idx) {
assert(Idx != RootIndex);

auto I = std::lower_bound(Children.begin(), Children.end(), Idx,
[](IndexTrieNode *a, unsigned i) {
return a->Index < i;
});
auto I =
std::lower_bound(Children.begin(), Children.end(), Idx,
[](IndexTrieNode *a, int i) { return a->Index < i; });
if (I != Children.end() && (*I)->Index == Idx)
return *I;
auto *N = new IndexTrieNode(Idx, this);
Expand Down
1,026 changes: 777 additions & 249 deletions include/swift/SIL/MemAccessUtils.h

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions include/swift/SIL/PatternMatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,16 @@ using BuiltinApplyTy = typename Apply_match<BuiltinValueKind, Tys...>::Ty;
// Define matchers for most of builtin instructions.
#include "swift/AST/Builtins.def"

#undef BUILTIN_UNARY_OP_MATCH_WITH_ARG_MATCHER
#undef BUILTIN_BINARY_OP_MATCH_WITH_ARG_MATCHER
#undef BUILTIN_VARARGS_OP_MATCH_WITH_ARG_MATCHER
#undef BUILTIN_CAST_OPERATION
#undef BUILTIN_CAST_OR_BITCAST_OPERATION
#undef BUILTIN_BINARY_OPERATION_ALL
#undef BUILTIN_BINARY_PREDICATE
#undef BUILTIN_MISC_OPERATION
#undef BUILTIN

//===
// Convenience compound builtin instructions matchers that succeed
// if any of the sub-matchers succeed.
Expand Down
39 changes: 18 additions & 21 deletions include/swift/SIL/Projection.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ inline bool isStrictSubSeqRelation(SubSeqRelation_t Seq) {

/// Extract an integer index from a SILValue.
///
/// Return true if IndexVal is a constant index representable as unsigned
/// Return true if IndexVal is a constant index representable as an
/// int. We do not support symbolic projections yet.
bool getIntegerIndex(SILValue IndexVal, unsigned &IndexConst);
bool getIntegerIndex(SILValue IndexVal, int &IndexConst);

/// The kind of projection that we are representing.
///
Expand Down Expand Up @@ -136,11 +136,18 @@ static inline bool isCastProjectionKind(ProjectionKind Kind) {
/// that immediately contains it.
///
/// This lightweight utility maps a SIL address projection to an index.
///
/// project_box does not have a projection index. At the SIL level, the box
/// storage is considered part of the same object as the. The box projection is
/// does not affect access path so that box projections can occur on distinct
/// phi paths in the address def-use chain.
struct ProjectionIndex {
static constexpr int TailIndex = std::numeric_limits<int>::max();

SILValue Aggregate;
unsigned Index;
int Index = std::numeric_limits<int>::min();

explicit ProjectionIndex(SILValue V) : Index(~0U) {
explicit ProjectionIndex(SILValue V) {
switch (V->getKind()) {
default:
break;
Expand All @@ -163,16 +170,9 @@ struct ProjectionIndex {
break;
}
case ValueKind::RefTailAddrInst: {
RefTailAddrInst *REA = cast<RefTailAddrInst>(V);
Index = 0;
Aggregate = REA->getOperand();
break;
}
case ValueKind::ProjectBoxInst: {
ProjectBoxInst *PBI = cast<ProjectBoxInst>(V);
// A box has only a single payload.
Index = 0;
Aggregate = PBI->getOperand();
RefTailAddrInst *RTA = cast<RefTailAddrInst>(V);
Index = TailIndex;
Aggregate = RTA->getOperand();
break;
}
case ValueKind::TupleElementAddrInst: {
Expand Down Expand Up @@ -233,8 +233,7 @@ class Projection {
: Projection(dyn_cast<SingleValueInstruction>(I)) {}
explicit Projection(SingleValueInstruction *I);

Projection(ProjectionKind Kind, unsigned NewIndex)
: Value(Kind, NewIndex) {}
Projection(ProjectionKind Kind, int NewIndex) : Value(Kind, NewIndex) {}

Projection(ProjectionKind Kind, TypeBase *Ptr)
: Value(Kind, Ptr) {}
Expand All @@ -252,10 +251,8 @@ class Projection {

/// Convenience method for getting the underlying index. Assumes that this
/// projection is valid. Otherwise it asserts.
unsigned getIndex() const {
return Value.getIndex();
}

int getIndex() const { return Value.getIndex(); }

unsigned getHash() const { return (unsigned)Value.getStorage(); }

/// Determine if I is a value projection instruction whose corresponding
Expand Down Expand Up @@ -359,7 +356,7 @@ class Projection {
return nullptr;
case ValueKind::IndexAddrInst: {
auto *i = cast<IndexAddrInst>(v);
unsigned scalar;
int scalar;
if (getIntegerIndex(i->getIndex(), scalar))
return i;
return nullptr;
Expand Down
8 changes: 3 additions & 5 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -5822,13 +5822,11 @@ class TupleElementAddrInst
/// object, including properties declared in a superclass.
unsigned getFieldIndex(NominalTypeDecl *decl, VarDecl *property);

/// Get the property for a struct or class by its unique index.
/// Get the property for a struct or class by its unique index, or nullptr if
/// the index does not match a property declared in this struct or class or
/// one its superclasses.
///
/// Precondition: \p decl must be a non-resilient struct or class.
///
/// Precondition: \p index must be the index of a stored property
/// (as returned by getFieldIndex()) which is declared
/// in \p decl, not in a superclass.
VarDecl *getIndexedField(NominalTypeDecl *decl, unsigned index);

/// A common base for instructions that require a cached field index.
Expand Down
7 changes: 7 additions & 0 deletions include/swift/SIL/SILModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "swift/AST/Builtins.h"
#include "swift/AST/SILLayout.h"
#include "swift/AST/SILOptions.h"
#include "swift/Basic/IndexTrie.h"
#include "swift/Basic/LangOptions.h"
#include "swift/Basic/ProfileCounter.h"
#include "swift/Basic/Range.h"
Expand Down Expand Up @@ -256,6 +257,10 @@ class SILModule {
/// The indexed profile data to be used for PGO, or nullptr.
std::unique_ptr<llvm::IndexedInstrProfReader> PGOReader;

/// A trie of integer indices that gives pointer identity to a path of
/// projections, shared between all functions in the module.
std::unique_ptr<IndexTrieNode> indexTrieRoot;

/// The options passed into this SILModule.
const SILOptions &Options;

Expand Down Expand Up @@ -655,6 +660,8 @@ class SILModule {
PGOReader = std::move(IPR);
}

IndexTrieNode *getIndexTrieRoot() { return indexTrieRoot.get(); }

/// Can value operations (copies and destroys) on the given lowered type
/// be performed in this module?
bool isTypeABIAccessible(SILType type,
Expand Down
15 changes: 3 additions & 12 deletions include/swift/SILOptimizer/Analysis/AccessSummaryAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
#ifndef SWIFT_SILOPTIMIZER_ANALYSIS_ACCESS_SUMMARY_ANALYSIS_H_
#define SWIFT_SILOPTIMIZER_ANALYSIS_ACCESS_SUMMARY_ANALYSIS_H_

#include "swift/Basic/IndexTrie.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SILOptimizer/Analysis/BottomUpIPAnalysis.h"
#include "swift/SILOptimizer/Utils/IndexTrie.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"

Expand Down Expand Up @@ -173,22 +173,13 @@ class AccessSummaryAnalysis : public BottomUpIPAnalysis {

llvm::SpecificBumpPtrAllocator<FunctionInfo> Allocator;

/// A trie of integer indices that gives pointer identity to a path of
/// projections. This is shared between all functions in the module.
std::unique_ptr<IndexTrieNode> SubPathTrie;

public:
AccessSummaryAnalysis() : BottomUpIPAnalysis(SILAnalysisKind::AccessSummary) {
SubPathTrie.reset(new IndexTrieNode());
}
AccessSummaryAnalysis()
: BottomUpIPAnalysis(SILAnalysisKind::AccessSummary) {}

/// Returns a summary of the accesses performed by the given function.
const FunctionSummary &getOrCreateSummary(SILFunction *Fn);

IndexTrieNode *getSubPathTrieRoot() {
return SubPathTrie.get();
}

/// Returns an IndexTrieNode that represents the single subpath accessed from
/// BAI or the root if no such node exists.
const IndexTrieNode *findSubPathAccessed(BeginAccessInst *BAI);
Expand Down
25 changes: 20 additions & 5 deletions include/swift/SILOptimizer/Analysis/ValueTracking.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ bool pointsToLocalObject(SILValue V);
/// Returns true if \p V is a uniquely identified address or reference. Two
/// uniquely identified pointers with distinct roots cannot alias. However, a
/// uniquely identified pointer may alias with unidentified pointers. For
/// example, the uniquely identified pointer may escape to a call that returns an
/// alias of that pointer.
/// example, the uniquely identified pointer may escape to a call that returns
/// an alias of that pointer.
///
/// It may be any of:
///
Expand All @@ -53,10 +53,25 @@ bool pointsToLocalObject(SILValue V);
///
/// - an address projection based on an exclusive argument with no levels of
/// indirection (e.g. ref_element_addr, project_box, etc.).
///
/// TODO: Fold this into the AccessedStorage API. pointsToLocalObject should be
/// performed by AccessedStorage::isUniquelyIdentified.
inline bool isUniquelyIdentified(SILValue V) {
return pointsToLocalObject(V)
|| (V->getType().isAddress()
&& isExclusiveArgument(getAccessedAddress(V)));
SILValue objectRef = V;
if (V->getType().isAddress()) {
auto storage = AccessedStorage::compute(V);
if (!storage)
return false;

if (storage.isUniquelyIdentified())
return true;

if (!storage.isObjectAccess())
return false;

objectRef = storage.getObject();
}
return pointsToLocalObject(objectRef);
}

enum class IsZeroKind {
Expand Down
2 changes: 2 additions & 0 deletions include/swift/SILOptimizer/PassManager/Passes.def
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ PASS(AccessSummaryDumper, "access-summary-dump",
"Dump Address Parameter Access Summary")
PASS(AccessedStorageAnalysisDumper, "accessed-storage-analysis-dump",
"Dump Accessed Storage Analysis Summaries")
PASS(AccessPathVerification, "access-path-verification",
"Verify Access Paths (and Accessed Storage)")
PASS(AccessedStorageDumper, "accessed-storage-dump",
"Dump Accessed Storage Information")
PASS(AccessMarkerElimination, "access-marker-elim",
Expand Down
2 changes: 1 addition & 1 deletion lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4125,7 +4125,7 @@ void IRGenSILFunction::visitRefTailAddrInst(RefTailAddrInst *i) {
}

static bool isInvariantAddress(SILValue v) {
SILValue accessedAddress = getAccessedAddress(v);
SILValue accessedAddress = getTypedAccessAddress(v);
if (auto *ptrRoot = dyn_cast<PointerToAddressInst>(accessedAddress)) {
return ptrRoot->isInvariant();
}
Expand Down
22 changes: 15 additions & 7 deletions lib/SIL/IR/SILInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1345,15 +1345,23 @@ unsigned swift::getFieldIndex(NominalTypeDecl *decl, VarDecl *field) {

/// Get the property for a struct or class by its unique index.
VarDecl *swift::getIndexedField(NominalTypeDecl *decl, unsigned index) {
if (auto *classDecl = dyn_cast<ClassDecl>(decl)) {
for (auto *superDecl = classDecl->getSuperclassDecl(); superDecl != nullptr;
superDecl = superDecl->getSuperclassDecl()) {
assert(index >= superDecl->getStoredProperties().size()
&& "field index cannot refer to a superclass field");
index -= superDecl->getStoredProperties().size();
if (auto *structDecl = dyn_cast<StructDecl>(decl)) {
return structDecl->getStoredProperties()[index];
}
auto *classDecl = cast<ClassDecl>(decl);
SmallVector<ClassDecl *, 3> superclasses;
for (auto *superDecl = classDecl; superDecl != nullptr;
superDecl = superDecl->getSuperclassDecl()) {
superclasses.push_back(superDecl);
}
std::reverse(superclasses.begin(), superclasses.end());
for (auto *superDecl : superclasses) {
if (index < superDecl->getStoredProperties().size()) {
return superDecl->getStoredProperties()[index];
}
index -= superDecl->getStoredProperties().size();
}
return decl->getStoredProperties()[index];
return nullptr;
}

unsigned FieldIndexCacheBase::cacheFieldIndex() {
Expand Down
3 changes: 2 additions & 1 deletion lib/SIL/IR/SILModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ class SILModule::SerializationCallback final

SILModule::SILModule(llvm::PointerUnion<FileUnit *, ModuleDecl *> context,
Lowering::TypeConverter &TC, const SILOptions &Options)
: Stage(SILStage::Raw), Options(Options), serialized(false),
: Stage(SILStage::Raw), indexTrieRoot(new IndexTrieNode()),
Options(Options), serialized(false),
regDeserializationNotificationHandlerForNonTransparentFuncOME(false),
regDeserializationNotificationHandlerForAllFuncOME(false),
SerializeSILAction(), Types(TC) {
Expand Down
Loading

0 comments on commit fd8f723

Please sign in to comment.