Skip to content

Commit 8dc7ae5

Browse files
committed
Implement a type expansion analysis pass. This pass caches the expansion of a type to its individual fields. i.e. a map
between SILType and a list of ProjectionPath is cached. This pass is immutable and never invalidated. Redundant load elimination and dead store elimination use this pass to improve compilation time. I see the hit rate of the cache to be ~95%. Without the pass. ---------------- Running Time Self (ms) Symbol Name 16338.0ms 28.2% 62.0 swift::SILPassManager::runFunctionPasses(llvm::ArrayRef<swift::SILFunctionTransform*>) 2716.0ms 4.6% 5.0 (anonymous namespace)::SimplifyCFGPass::run() 2654.0ms 4.5% 12.0 (anonymous namespace)::ARCSequenceOpts::run() 2218.0ms 3.8% 7.0 (anonymous namespace)::SILCombine::run() 1660.0ms 2.8% 66.0 (anonymous namespace)::SILCSE::run() 1625.0ms 2.8% 120.0 (anonymous namespace)::RedundantLoadElimination::run() 1491.0ms 2.5% 35.0 (anonymous namespace)::DeadStoreElimination::run() 1213.0ms 2.0% 1.0 swift::BottomUpFunctionOrder::getFunctions() 777.0ms 1.3% 127.0 (anonymous namespace)::DCE::run() 381.0ms 0.6% 2.0 (anonymous namespace)::SILCodeMotion::run() With the pass. -------------- Running Time Self (ms) Symbol Name 15866.0ms 26.8% 73.0 swift::SILPassManager::runFunctionPasses(llvm::ArrayRef<swift::SILFunctionTransform*>) 2736.0ms 4.6% 6.0 (anonymous namespace)::SimplifyCFGPass::run() 2696.0ms 4.5% 14. (anonymous namespace)::ARCSequenceOpts::run() 2393.0ms 4.0% 7.0 (anonymous namespace)::SILCombine::run() 1673.0ms 2.8% 81. (anonymous namespace)::SILCSE::run() 1290.0ms 2.1% 2.0 swift::BottomUpFunctionOrder::getFunctions() 1288.0ms 2.1% 17.0 swift::BottomUpFunctionOrder::FindSCCs(swift::SILModule&) 1140.0ms 1.9% 138.0 (anonymous namespace)::RedundantLoadElimination::run() 1119.0ms 1.8% 21.0 (anonymous namespace)::DeadStoreElimination::run() 749.0ms 1.2% 147.0 (anonymous namespace)::DCE::run() 379.0ms 0.6% 7.0 (anonymous namespace)::SILCodeMotion::run() 256.0ms 0.4% 11.0 (anonymous namespace)::ABCOpt::run()
1 parent a6e7fdb commit 8dc7ae5

File tree

9 files changed

+190
-87
lines changed

9 files changed

+190
-87
lines changed

include/swift/SIL/MemLocation.h

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#define SWIFT_SIL_MEMLOCATION_H
2121

2222
#include "swift/SILAnalysis/AliasAnalysis.h"
23+
#include "swift/SILAnalysis/TypeExpansionAnalysis.h"
2324
#include "swift/SIL/Projection.h"
2425
#include "swift/SILPasses/Utils/Local.h"
2526
#include "swift/SILAnalysis/ValueTracking.h"
@@ -68,8 +69,12 @@ class SILValueProjection {
6869
SILValueProjection() : Base(), Kind(NormalKey) {}
6970
SILValueProjection(KeyKind Kind) : Base(), Kind(Kind) {}
7071
SILValueProjection(SILValue B) : Base(B), Kind(NormalKey) {}
71-
SILValueProjection(SILValue B, ProjectionPath &P, KeyKind Kind = NormalKey)
72-
: Base(B), Kind(Kind), Path(std::move(P)) {}
72+
SILValueProjection(SILValue B, const ProjectionPath &P, KeyKind Kind = NormalKey)
73+
: Base(B), Kind(Kind) {
74+
ProjectionPath T;
75+
T.append(P);
76+
Path = std::move(T);
77+
}
7378

7479
/// Destructors.
7580
virtual ~SILValueProjection() {}
@@ -273,7 +278,7 @@ class LoadStoreValue : public SILValueProjection {
273278
/// Constructors.
274279
LoadStoreValue() : SILValueProjection(), IsCoveringValue(false) {}
275280
LoadStoreValue(SILValue B) : SILValueProjection(B), IsCoveringValue(false) {}
276-
LoadStoreValue(SILValue B, ProjectionPath &P)
281+
LoadStoreValue(SILValue B, const ProjectionPath &P)
277282
: SILValueProjection(B, P), IsCoveringValue(false) {}
278283

279284
/// Copy constructor.
@@ -385,7 +390,7 @@ class MemLocation : public SILValueProjection {
385390
: SILValueProjection(B, P, Kind) {}
386391
MemLocation(KeyKind Kind) : SILValueProjection(Kind) {}
387392
/// Use the concatenation of the 2 ProjectionPaths as the Path.
388-
MemLocation(SILValue B, ProjectionPath &P1, ProjectionPath &P2)
393+
MemLocation(SILValue B, const ProjectionPath &P1, const ProjectionPath &P2)
389394
: SILValueProjection(B) {
390395
ProjectionPath T;
391396
T.append(P1);
@@ -447,16 +452,18 @@ class MemLocation : public SILValueProjection {
447452
/// fields. Therefore, we expand all the operations on aggregates onto
448453
/// individual fields and process them separately.
449454
static void expand(MemLocation &Base, SILModule *Mod, MemLocationList &Locs,
450-
TypeExpansionMap &TypeExpansionVault);
455+
TypeExpansionAnalysis *TE);
451456

452457
/// Given a set of locations derived from the same base, try to merge/reduce
453458
/// them into smallest number of MemLocations possible.
454-
static void reduce(MemLocation &Base, SILModule *Mod, MemLocationSet &Locs);
459+
static void reduce(MemLocation &Base, SILModule *Mod, MemLocationSet &Locs,
460+
TypeExpansionAnalysis *TE);
455461

456462
/// Given a memory location and a SILValue, expand the location into its
457463
/// individual fields and the values that is in each individual field.
458464
static void expandWithValues(MemLocation &Base, SILValue &Val, SILModule *Mod,
459-
MemLocationList &Locs, LoadStoreValueList &Vals);
465+
MemLocationList &Locs, LoadStoreValueList &Vals,
466+
TypeExpansionAnalysis *TE);
460467

461468
/// Given a memory location and a map between the expansions of the location
462469
/// and their corresponding values, try to come up with a single SILValue this
@@ -467,19 +474,20 @@ class MemLocation : public SILValueProjection {
467474
/// concrete (i.e. not coverings set) available value in LocAndVal.
468475
static SILValue reduceWithValues(MemLocation &Base, SILModule *Mod,
469476
MemLocationValueMap &LocAndVal,
470-
SILInstruction *InsertPt);
477+
SILInstruction *InsertPt,
478+
TypeExpansionAnalysis *TE);
471479

472480
/// Enumerate the given Mem MemLocation.
473481
static void enumerateMemLocation(SILModule *M, SILValue Mem,
474482
std::vector<MemLocation> &MemLocationVault,
475483
MemLocationIndexMap &LocToBit,
476-
TypeExpansionMap &TypeExpansionVault);
484+
TypeExpansionAnalysis *TE);
477485

478486
/// Enumerate all the locations in the function.
479487
static void enumerateMemLocations(SILFunction &F,
480488
std::vector<MemLocation> &MemLocationVault,
481489
MemLocationIndexMap &LocToBit,
482-
TypeExpansionMap &TypeExpansionVault);
490+
TypeExpansionAnalysis *TE);
483491
};
484492

485493
static inline llvm::hash_code hash_value(const MemLocation &L) {

include/swift/SILAnalysis/Analysis.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,6 @@ ANALYSIS(PostDominance)
3737
ANALYSIS(PostOrder)
3838
ANALYSIS(RCIdentity)
3939
ANALYSIS(SideEffect)
40+
ANALYSIS(TypeExpansion)
4041

4142
#undef ANALYSIS
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//===--- TypeExpansionAnalysis.h ------------------------------*- C++ -*------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
#ifndef SWIFT_SILANALYSIS_TYPEEXPANSIONANALYSIS_H
13+
#define SWIFT_SILANALYSIS_TYPEEXPANSIONANALYSIS_H
14+
15+
#include "swift/SIL/Projection.h"
16+
#include "swift/SIL/SILValue.h"
17+
#include "swift/SILAnalysis/Analysis.h"
18+
#include "llvm/ADT/DenseMap.h"
19+
20+
namespace swift {
21+
22+
/// This analysis determines memory effects during destruction.
23+
class TypeExpansionAnalysis : public SILAnalysis {
24+
using TypeExpansionMap = llvm::DenseMap<SILType, ProjectionPathList>;
25+
/// Caches the type to leaf node expansion.
26+
TypeExpansionMap LeafTECache;
27+
/// Caches the type to each node expansion, including intermediate nodes as
28+
/// well as leaf nodes in the type tree.
29+
TypeExpansionMap NodeTECache;
30+
31+
public:
32+
TypeExpansionAnalysis(SILModule *M)
33+
: SILAnalysis(AnalysisKind::TypeExpansion) {}
34+
35+
static bool classof(const SILAnalysis *S) {
36+
return S->getKind() == AnalysisKind::TypeExpansion;
37+
}
38+
39+
/// Return ProjectionPath to every leaf node of the given type.
40+
const ProjectionPathList &getTypeLeafExpansion(SILType B, SILModule *Mod);
41+
/// Returns the ProjectionPath to every leaf and intermediate node of the
42+
/// given type.
43+
const ProjectionPathList &getTypeNodeExpansion(SILType B, SILModule *Mod);
44+
};
45+
}
46+
#endif

lib/SIL/MemLocation.cpp

Lines changed: 25 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -108,38 +108,27 @@ void MemLocation::getFirstLevelMemLocations(MemLocationList &Locs,
108108
}
109109

110110
void MemLocation::expand(MemLocation &Base, SILModule *M, MemLocationList &Locs,
111-
TypeExpansionMap &TECache) {
111+
TypeExpansionAnalysis *TE) {
112112
// To expand a memory location to its indivisible parts, we first get the
113113
// address projection paths from the accessed type to each indivisible field,
114114
// i.e. leaf nodes, then we append these projection paths to the Base.
115-
SILType BaseTy = Base.getType();
116-
if (TECache.find(BaseTy) == TECache.end()) {
117-
// There is no cached expansion for this type, build and cache it now.
118-
ProjectionPathList Paths;
119-
ProjectionPath::expandTypeIntoLeafProjectionPaths(BaseTy, M, Paths);
120-
for (auto &P : Paths) {
121-
TECache[BaseTy].push_back(std::move(P.getValue()));
122-
}
123-
}
124-
115+
//
125116
// Construct the MemLocation by appending the projection path from the
126117
// accessed node to the leaf nodes.
127118
ProjectionPath &BasePath = Base.getPath().getValue();
128-
for (auto &P : TECache[BaseTy]) {
119+
for (const auto &P : TE->getTypeLeafExpansion(Base.getType(), M)) {
129120
Locs.push_back(MemLocation(Base.getBase(), P.getValue(), BasePath));
130121
}
131122
}
132123

133-
void MemLocation::reduce(MemLocation &Base, SILModule *M, MemLocationSet &Locs) {
124+
void MemLocation::reduce(MemLocation &Base, SILModule *M, MemLocationSet &Locs,
125+
TypeExpansionAnalysis *TE) {
134126
// First, construct the MemLocation by appending the projection path from the
135127
// accessed node to the leaf nodes.
136128
MemLocationList Nodes;
137-
ProjectionPathList Paths;
138-
ProjectionPath::expandTypeIntoNodeProjectionPaths(Base.getType(), M,
139-
Paths);
140129
ProjectionPath &BasePath = Base.getPath().getValue();
141-
for (auto &X : Paths) {
142-
Nodes.push_back(MemLocation(Base.getBase(), X.getValue(), BasePath));
130+
for (const auto &P : TE->getTypeNodeExpansion(Base.getType(), M)) {
131+
Nodes.push_back(MemLocation(Base.getBase(), P.getValue(), BasePath));
143132
}
144133

145134
// Second, go from leaf nodes to their parents. This guarantees that at the
@@ -172,41 +161,37 @@ void MemLocation::reduce(MemLocation &Base, SILModule *M, MemLocationSet &Locs)
172161
}
173162

174163
void MemLocation::expandWithValues(MemLocation &Base, SILValue &Val,
175-
SILModule *Mod, MemLocationList &Locs,
176-
LoadStoreValueList &Vals) {
164+
SILModule *M, MemLocationList &Locs,
165+
LoadStoreValueList &Vals,
166+
TypeExpansionAnalysis *TE) {
177167
// To expand a memory location to its indivisible parts, we first get the
178168
// projection paths from the accessed type to each indivisible field, i.e.
179169
// leaf nodes, then we append these projection paths to the Base.
180-
ProjectionPathList Paths;
181-
ProjectionPath::expandTypeIntoLeafProjectionPaths(Base.getType(), Mod,
182-
Paths);
183-
170+
//
184171
// Construct the MemLocation and LoadStoreValues by appending the projection
185172
// path
186173
// from the accessed node to the leaf nodes.
187174
ProjectionPath &BasePath = Base.getPath().getValue();
188-
for (auto &X : Paths) {
189-
Locs.push_back(MemLocation(Base.getBase(), X.getValue(), BasePath));
190-
Vals.push_back(LoadStoreValue(Val, X.getValue()));
175+
for (const auto &P : TE->getTypeLeafExpansion(Base.getType(), M)) {
176+
Locs.push_back(MemLocation(Base.getBase(), P.getValue(), BasePath));
177+
Vals.push_back(LoadStoreValue(Val, P.getValue()));
191178
}
192179
}
193180

194-
SILValue MemLocation::reduceWithValues(MemLocation &Base, SILModule *Mod,
181+
SILValue MemLocation::reduceWithValues(MemLocation &Base, SILModule *M,
195182
MemLocationValueMap &Values,
196-
SILInstruction *InsertPt) {
183+
SILInstruction *InsertPt,
184+
TypeExpansionAnalysis *TE) {
197185
// Walk bottom up the projection tree, try to reason about how to construct
198186
// a single SILValue out of all the available values for all the memory
199187
// locations.
200188
//
201189
// First, get a list of all the leaf nodes and intermediate nodes for the
202190
// Base memory location.
203191
MemLocationList ALocs;
204-
ProjectionPathList Paths;
205-
ProjectionPath::expandTypeIntoNodeProjectionPaths(Base.getType(), Mod,
206-
Paths);
207192
ProjectionPath &BasePath = Base.getPath().getValue();
208-
for (auto &X : Paths) {
209-
ALocs.push_back(MemLocation(Base.getBase(), X.getValue(), BasePath));
193+
for (const auto &P : TE->getTypeNodeExpansion(Base.getType(), M)) {
194+
ALocs.push_back(MemLocation(Base.getBase(), P.getValue(), BasePath));
210195
}
211196

212197
// Second, go from leaf nodes to their parents. This guarantees that at the
@@ -216,7 +201,7 @@ SILValue MemLocation::reduceWithValues(MemLocation &Base, SILModule *Mod,
216201
//
217202
// Reached the end of the projection tree, this is a leaf node.
218203
MemLocationList FirstLevel;
219-
I->getFirstLevelMemLocations(FirstLevel, Mod);
204+
I->getFirstLevelMemLocations(FirstLevel, M);
220205
if (FirstLevel.empty())
221206
continue;
222207

@@ -287,7 +272,7 @@ SILValue MemLocation::reduceWithValues(MemLocation &Base, SILModule *Mod,
287272
void MemLocation::enumerateMemLocation(SILModule *M, SILValue Mem,
288273
std::vector<MemLocation> &LV,
289274
MemLocationIndexMap &BM,
290-
TypeExpansionMap &TV) {
275+
TypeExpansionAnalysis *TE) {
291276
// Construct a Location to represent the memory written by this instruction.
292277
MemLocation L(Mem);
293278

@@ -299,7 +284,7 @@ void MemLocation::enumerateMemLocation(SILModule *M, SILValue Mem,
299284
// Expand the given Mem into individual fields and add them to the
300285
// locationvault.
301286
MemLocationList Locs;
302-
MemLocation::expand(L, M, Locs, TV);
287+
MemLocation::expand(L, M, Locs, TE);
303288
for (auto &Loc : Locs) {
304289
BM[Loc] = LV.size();
305290
LV.push_back(Loc);
@@ -309,7 +294,7 @@ void MemLocation::enumerateMemLocation(SILModule *M, SILValue Mem,
309294
void MemLocation::enumerateMemLocations(SILFunction &F,
310295
std::vector<MemLocation> &LV,
311296
MemLocationIndexMap &BM,
312-
TypeExpansionMap &TV) {
297+
TypeExpansionAnalysis *TE) {
313298
// Enumerate all locations accessed by the loads or stores.
314299
//
315300
// TODO: process more instructions as we process more instructions in
@@ -319,9 +304,9 @@ void MemLocation::enumerateMemLocations(SILFunction &F,
319304
for (auto &B : F) {
320305
for (auto &I : B) {
321306
if (auto *LI = dyn_cast<LoadInst>(&I)) {
322-
enumerateMemLocation(&I.getModule(), LI->getOperand(), LV, BM, TV);
307+
enumerateMemLocation(&I.getModule(), LI->getOperand(), LV, BM, TE);
323308
} else if (auto *SI = dyn_cast<StoreInst>(&I)) {
324-
enumerateMemLocation(&I.getModule(), SI->getDest(), LV, BM, TV);
309+
enumerateMemLocation(&I.getModule(), SI->getDest(), LV, BM, TE);
325310
}
326311
}
327312
}

lib/SILAnalysis/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@ add_swift_library(swiftSILAnalysis
1818
RCIdentityAnalysis.cpp
1919
SideEffectAnalysis.cpp
2020
SimplifyInstruction.cpp
21+
TypeExpansionAnalysis.cpp
2122
ValueTracking.cpp
2223
LINK_LIBRARIES swiftSILPassesUtils)
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#include "swift/SILAnalysis/TypeExpansionAnalysis.h"
2+
#include "swift/SIL/SILInstruction.h"
3+
#include "swift/SIL/SILModule.h"
4+
#include "llvm/Support/Debug.h"
5+
6+
#define DEBUG_TYPE "typeexpansion-analysis"
7+
8+
using namespace swift;
9+
10+
// The MemoryBehavior Cache must not grow beyond this size.
11+
// We limit the size of the MB cache to 2**12 because we want to limit the
12+
// memory usage of this cache.
13+
static const int TypeExpansionAnalysisMaxCacheSize = 4096;
14+
15+
const ProjectionPathList &
16+
TypeExpansionAnalysis::getTypeLeafExpansion(SILType B, SILModule *Mod) {
17+
// Check whether we have the type expansion.
18+
if (LeafTECache.find(B) != LeafTECache.end()) {
19+
return LeafTECache.find(B)->second;
20+
}
21+
22+
// Flush the cache if the size of the cache is too large.
23+
if (LeafTECache.size() > TypeExpansionAnalysisMaxCacheSize) {
24+
LeafTECache.clear();
25+
}
26+
27+
// Need to build the type expansion.
28+
LeafTECache[B] = ProjectionPathList();
29+
ProjectionPath::expandTypeIntoLeafProjectionPaths(B, Mod, LeafTECache[B]);
30+
return LeafTECache[B];
31+
}
32+
33+
const ProjectionPathList &
34+
TypeExpansionAnalysis::getTypeNodeExpansion(SILType B, SILModule *Mod) {
35+
// Check whether we have the type expansion.
36+
if (NodeTECache.find(B) != NodeTECache.end()) {
37+
return NodeTECache.find(B)->second;
38+
}
39+
40+
// Flush the cache if the size of the cache is too large.
41+
if (NodeTECache.size() > TypeExpansionAnalysisMaxCacheSize) {
42+
NodeTECache.clear();
43+
}
44+
45+
// Need to build the type expansion.
46+
NodeTECache[B] = ProjectionPathList();
47+
ProjectionPath::expandTypeIntoNodeProjectionPaths(B, Mod, NodeTECache[B]);
48+
return NodeTECache[B];
49+
}
50+
51+
SILAnalysis *swift::createTypeExpansionAnalysis(SILModule *M) {
52+
return new TypeExpansionAnalysis(M);
53+
}

0 commit comments

Comments
 (0)