Skip to content

Commit fd8f723

Browse files
authored
Merge pull request #34126 from atrick/add-accesspath
Add an AccessPath abstraction and formalize memory access
2 parents 68b790f + 5e0c8f9 commit fd8f723

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+4034
-645
lines changed

docs/SILProgrammersManual.md

Lines changed: 462 additions & 0 deletions
Large diffs are not rendered by default.

include/swift/SILOptimizer/Utils/IndexTrie.h renamed to include/swift/Basic/IndexTrie.h

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef SWIFT_SILOPTIMIZER_UTILS_INDEXTREE_H
1414
#define SWIFT_SILOPTIMIZER_UTILS_INDEXTREE_H
1515

16+
#include "swift/Basic/LLVM.h"
1617
#include "llvm/ADT/ArrayRef.h"
1718
#include "llvm/ADT/SmallVector.h"
1819
#include <algorithm>
@@ -21,15 +22,18 @@ namespace swift {
2122

2223
// Trie node representing a sequence of unsigned integer indices.
2324
class IndexTrieNode {
24-
static const unsigned RootIdx = ~0U;
25-
unsigned Index;
25+
public:
26+
static const int RootIndex = std::numeric_limits<int>::min();
27+
28+
private:
29+
int Index;
2630
llvm::SmallVector<IndexTrieNode*, 8> Children;
2731
IndexTrieNode *Parent;
2832

2933
public:
30-
IndexTrieNode(): Index(RootIdx), Parent(nullptr) {}
34+
IndexTrieNode() : Index(RootIndex), Parent(nullptr) {}
3135

32-
explicit IndexTrieNode(unsigned V, IndexTrieNode *P): Index(V), Parent(P) {}
36+
explicit IndexTrieNode(int V, IndexTrieNode *P) : Index(V), Parent(P) {}
3337

3438
IndexTrieNode(IndexTrieNode &) =delete;
3539
IndexTrieNode &operator=(const IndexTrieNode&) =delete;
@@ -39,19 +43,18 @@ class IndexTrieNode {
3943
delete N;
4044
}
4145

42-
bool isRoot() const { return Index == RootIdx; }
46+
bool isRoot() const { return Index == RootIndex; }
4347

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

46-
unsigned getIndex() const { return Index; }
50+
int getIndex() const { return Index; }
4751

48-
IndexTrieNode *getChild(unsigned Idx) {
49-
assert(Idx != RootIdx);
52+
IndexTrieNode *getChild(int Idx) {
53+
assert(Idx != RootIndex);
5054

51-
auto I = std::lower_bound(Children.begin(), Children.end(), Idx,
52-
[](IndexTrieNode *a, unsigned i) {
53-
return a->Index < i;
54-
});
55+
auto I =
56+
std::lower_bound(Children.begin(), Children.end(), Idx,
57+
[](IndexTrieNode *a, int i) { return a->Index < i; });
5558
if (I != Children.end() && (*I)->Index == Idx)
5659
return *I;
5760
auto *N = new IndexTrieNode(Idx, this);

include/swift/SIL/MemAccessUtils.h

Lines changed: 777 additions & 249 deletions
Large diffs are not rendered by default.

include/swift/SIL/PatternMatch.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,16 @@ using BuiltinApplyTy = typename Apply_match<BuiltinValueKind, Tys...>::Ty;
668668
// Define matchers for most of builtin instructions.
669669
#include "swift/AST/Builtins.def"
670670

671+
#undef BUILTIN_UNARY_OP_MATCH_WITH_ARG_MATCHER
672+
#undef BUILTIN_BINARY_OP_MATCH_WITH_ARG_MATCHER
673+
#undef BUILTIN_VARARGS_OP_MATCH_WITH_ARG_MATCHER
674+
#undef BUILTIN_CAST_OPERATION
675+
#undef BUILTIN_CAST_OR_BITCAST_OPERATION
676+
#undef BUILTIN_BINARY_OPERATION_ALL
677+
#undef BUILTIN_BINARY_PREDICATE
678+
#undef BUILTIN_MISC_OPERATION
679+
#undef BUILTIN
680+
671681
//===
672682
// Convenience compound builtin instructions matchers that succeed
673683
// if any of the sub-matchers succeed.

include/swift/SIL/Projection.h

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ inline bool isStrictSubSeqRelation(SubSeqRelation_t Seq) {
6767

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

7474
/// The kind of projection that we are representing.
7575
///
@@ -136,11 +136,18 @@ static inline bool isCastProjectionKind(ProjectionKind Kind) {
136136
/// that immediately contains it.
137137
///
138138
/// This lightweight utility maps a SIL address projection to an index.
139+
///
140+
/// project_box does not have a projection index. At the SIL level, the box
141+
/// storage is considered part of the same object as the. The box projection is
142+
/// does not affect access path so that box projections can occur on distinct
143+
/// phi paths in the address def-use chain.
139144
struct ProjectionIndex {
145+
static constexpr int TailIndex = std::numeric_limits<int>::max();
146+
140147
SILValue Aggregate;
141-
unsigned Index;
148+
int Index = std::numeric_limits<int>::min();
142149

143-
explicit ProjectionIndex(SILValue V) : Index(~0U) {
150+
explicit ProjectionIndex(SILValue V) {
144151
switch (V->getKind()) {
145152
default:
146153
break;
@@ -163,16 +170,9 @@ struct ProjectionIndex {
163170
break;
164171
}
165172
case ValueKind::RefTailAddrInst: {
166-
RefTailAddrInst *REA = cast<RefTailAddrInst>(V);
167-
Index = 0;
168-
Aggregate = REA->getOperand();
169-
break;
170-
}
171-
case ValueKind::ProjectBoxInst: {
172-
ProjectBoxInst *PBI = cast<ProjectBoxInst>(V);
173-
// A box has only a single payload.
174-
Index = 0;
175-
Aggregate = PBI->getOperand();
173+
RefTailAddrInst *RTA = cast<RefTailAddrInst>(V);
174+
Index = TailIndex;
175+
Aggregate = RTA->getOperand();
176176
break;
177177
}
178178
case ValueKind::TupleElementAddrInst: {
@@ -233,8 +233,7 @@ class Projection {
233233
: Projection(dyn_cast<SingleValueInstruction>(I)) {}
234234
explicit Projection(SingleValueInstruction *I);
235235

236-
Projection(ProjectionKind Kind, unsigned NewIndex)
237-
: Value(Kind, NewIndex) {}
236+
Projection(ProjectionKind Kind, int NewIndex) : Value(Kind, NewIndex) {}
238237

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

253252
/// Convenience method for getting the underlying index. Assumes that this
254253
/// projection is valid. Otherwise it asserts.
255-
unsigned getIndex() const {
256-
return Value.getIndex();
257-
}
258-
254+
int getIndex() const { return Value.getIndex(); }
255+
259256
unsigned getHash() const { return (unsigned)Value.getStorage(); }
260257

261258
/// Determine if I is a value projection instruction whose corresponding
@@ -359,7 +356,7 @@ class Projection {
359356
return nullptr;
360357
case ValueKind::IndexAddrInst: {
361358
auto *i = cast<IndexAddrInst>(v);
362-
unsigned scalar;
359+
int scalar;
363360
if (getIntegerIndex(i->getIndex(), scalar))
364361
return i;
365362
return nullptr;

include/swift/SIL/SILInstruction.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5822,13 +5822,11 @@ class TupleElementAddrInst
58225822
/// object, including properties declared in a superclass.
58235823
unsigned getFieldIndex(NominalTypeDecl *decl, VarDecl *property);
58245824

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

58345832
/// A common base for instructions that require a cached field index.

include/swift/SIL/SILModule.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/AST/Builtins.h"
2222
#include "swift/AST/SILLayout.h"
2323
#include "swift/AST/SILOptions.h"
24+
#include "swift/Basic/IndexTrie.h"
2425
#include "swift/Basic/LangOptions.h"
2526
#include "swift/Basic/ProfileCounter.h"
2627
#include "swift/Basic/Range.h"
@@ -256,6 +257,10 @@ class SILModule {
256257
/// The indexed profile data to be used for PGO, or nullptr.
257258
std::unique_ptr<llvm::IndexedInstrProfReader> PGOReader;
258259

260+
/// A trie of integer indices that gives pointer identity to a path of
261+
/// projections, shared between all functions in the module.
262+
std::unique_ptr<IndexTrieNode> indexTrieRoot;
263+
259264
/// The options passed into this SILModule.
260265
const SILOptions &Options;
261266

@@ -655,6 +660,8 @@ class SILModule {
655660
PGOReader = std::move(IPR);
656661
}
657662

663+
IndexTrieNode *getIndexTrieRoot() { return indexTrieRoot.get(); }
664+
658665
/// Can value operations (copies and destroys) on the given lowered type
659666
/// be performed in this module?
660667
bool isTypeABIAccessible(SILType type,

include/swift/SILOptimizer/Analysis/AccessSummaryAnalysis.h

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@
1919
#ifndef SWIFT_SILOPTIMIZER_ANALYSIS_ACCESS_SUMMARY_ANALYSIS_H_
2020
#define SWIFT_SILOPTIMIZER_ANALYSIS_ACCESS_SUMMARY_ANALYSIS_H_
2121

22+
#include "swift/Basic/IndexTrie.h"
2223
#include "swift/SIL/SILFunction.h"
2324
#include "swift/SIL/SILInstruction.h"
2425
#include "swift/SILOptimizer/Analysis/BottomUpIPAnalysis.h"
25-
#include "swift/SILOptimizer/Utils/IndexTrie.h"
2626
#include "llvm/ADT/DenseMap.h"
2727
#include "llvm/ADT/SmallVector.h"
2828

@@ -173,22 +173,13 @@ class AccessSummaryAnalysis : public BottomUpIPAnalysis {
173173

174174
llvm::SpecificBumpPtrAllocator<FunctionInfo> Allocator;
175175

176-
/// A trie of integer indices that gives pointer identity to a path of
177-
/// projections. This is shared between all functions in the module.
178-
std::unique_ptr<IndexTrieNode> SubPathTrie;
179-
180176
public:
181-
AccessSummaryAnalysis() : BottomUpIPAnalysis(SILAnalysisKind::AccessSummary) {
182-
SubPathTrie.reset(new IndexTrieNode());
183-
}
177+
AccessSummaryAnalysis()
178+
: BottomUpIPAnalysis(SILAnalysisKind::AccessSummary) {}
184179

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

188-
IndexTrieNode *getSubPathTrieRoot() {
189-
return SubPathTrie.get();
190-
}
191-
192183
/// Returns an IndexTrieNode that represents the single subpath accessed from
193184
/// BAI or the root if no such node exists.
194185
const IndexTrieNode *findSubPathAccessed(BeginAccessInst *BAI);

include/swift/SILOptimizer/Analysis/ValueTracking.h

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ bool pointsToLocalObject(SILValue V);
3939
/// Returns true if \p V is a uniquely identified address or reference. Two
4040
/// uniquely identified pointers with distinct roots cannot alias. However, a
4141
/// uniquely identified pointer may alias with unidentified pointers. For
42-
/// example, the uniquely identified pointer may escape to a call that returns an
43-
/// alias of that pointer.
42+
/// example, the uniquely identified pointer may escape to a call that returns
43+
/// an alias of that pointer.
4444
///
4545
/// It may be any of:
4646
///
@@ -53,10 +53,25 @@ bool pointsToLocalObject(SILValue V);
5353
///
5454
/// - an address projection based on an exclusive argument with no levels of
5555
/// indirection (e.g. ref_element_addr, project_box, etc.).
56+
///
57+
/// TODO: Fold this into the AccessedStorage API. pointsToLocalObject should be
58+
/// performed by AccessedStorage::isUniquelyIdentified.
5659
inline bool isUniquelyIdentified(SILValue V) {
57-
return pointsToLocalObject(V)
58-
|| (V->getType().isAddress()
59-
&& isExclusiveArgument(getAccessedAddress(V)));
60+
SILValue objectRef = V;
61+
if (V->getType().isAddress()) {
62+
auto storage = AccessedStorage::compute(V);
63+
if (!storage)
64+
return false;
65+
66+
if (storage.isUniquelyIdentified())
67+
return true;
68+
69+
if (!storage.isObjectAccess())
70+
return false;
71+
72+
objectRef = storage.getObject();
73+
}
74+
return pointsToLocalObject(objectRef);
6075
}
6176

6277
enum class IsZeroKind {

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ PASS(AccessSummaryDumper, "access-summary-dump",
7070
"Dump Address Parameter Access Summary")
7171
PASS(AccessedStorageAnalysisDumper, "accessed-storage-analysis-dump",
7272
"Dump Accessed Storage Analysis Summaries")
73+
PASS(AccessPathVerification, "access-path-verification",
74+
"Verify Access Paths (and Accessed Storage)")
7375
PASS(AccessedStorageDumper, "accessed-storage-dump",
7476
"Dump Accessed Storage Information")
7577
PASS(AccessMarkerElimination, "access-marker-elim",

lib/IRGen/IRGenSIL.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4125,7 +4125,7 @@ void IRGenSILFunction::visitRefTailAddrInst(RefTailAddrInst *i) {
41254125
}
41264126

41274127
static bool isInvariantAddress(SILValue v) {
4128-
SILValue accessedAddress = getAccessedAddress(v);
4128+
SILValue accessedAddress = getTypedAccessAddress(v);
41294129
if (auto *ptrRoot = dyn_cast<PointerToAddressInst>(accessedAddress)) {
41304130
return ptrRoot->isInvariant();
41314131
}

lib/SIL/IR/SILInstructions.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,15 +1345,23 @@ unsigned swift::getFieldIndex(NominalTypeDecl *decl, VarDecl *field) {
13451345

13461346
/// Get the property for a struct or class by its unique index.
13471347
VarDecl *swift::getIndexedField(NominalTypeDecl *decl, unsigned index) {
1348-
if (auto *classDecl = dyn_cast<ClassDecl>(decl)) {
1349-
for (auto *superDecl = classDecl->getSuperclassDecl(); superDecl != nullptr;
1350-
superDecl = superDecl->getSuperclassDecl()) {
1351-
assert(index >= superDecl->getStoredProperties().size()
1352-
&& "field index cannot refer to a superclass field");
1353-
index -= superDecl->getStoredProperties().size();
1348+
if (auto *structDecl = dyn_cast<StructDecl>(decl)) {
1349+
return structDecl->getStoredProperties()[index];
1350+
}
1351+
auto *classDecl = cast<ClassDecl>(decl);
1352+
SmallVector<ClassDecl *, 3> superclasses;
1353+
for (auto *superDecl = classDecl; superDecl != nullptr;
1354+
superDecl = superDecl->getSuperclassDecl()) {
1355+
superclasses.push_back(superDecl);
1356+
}
1357+
std::reverse(superclasses.begin(), superclasses.end());
1358+
for (auto *superDecl : superclasses) {
1359+
if (index < superDecl->getStoredProperties().size()) {
1360+
return superDecl->getStoredProperties()[index];
13541361
}
1362+
index -= superDecl->getStoredProperties().size();
13551363
}
1356-
return decl->getStoredProperties()[index];
1364+
return nullptr;
13571365
}
13581366

13591367
unsigned FieldIndexCacheBase::cacheFieldIndex() {

lib/SIL/IR/SILModule.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ class SILModule::SerializationCallback final
9494

9595
SILModule::SILModule(llvm::PointerUnion<FileUnit *, ModuleDecl *> context,
9696
Lowering::TypeConverter &TC, const SILOptions &Options)
97-
: Stage(SILStage::Raw), Options(Options), serialized(false),
97+
: Stage(SILStage::Raw), indexTrieRoot(new IndexTrieNode()),
98+
Options(Options), serialized(false),
9899
regDeserializationNotificationHandlerForNonTransparentFuncOME(false),
99100
regDeserializationNotificationHandlerForAllFuncOME(false),
100101
SerializeSILAction(), Types(TC) {

0 commit comments

Comments
 (0)