Skip to content

Commit 18da183

Browse files
committed
[CSBindings] Cache already computed type variable bindings
To avoid re-computing same bindings over and over again, let's try to keep a cache of active bindings and invalidate them as needed. Invalidate bindings conservatively when new constraints are introduced (even if such constraints are not going to result in new type bindings), and when type variables are assigned fixed types or merged together. Invalidation also makes sure to erase bindings of all adjacent type variables related to equivalence class of the variables in question. This significantly speeds up use-cases that have a lot of type variables such as collection literals with arbitrary nesting.
1 parent 2f8a4db commit 18da183

File tree

6 files changed

+60
-9
lines changed

6 files changed

+60
-9
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,26 @@ Optional<ConstraintSystem::PotentialBindings>
2525
ConstraintSystem::determineBestBindings() {
2626
// Look for potential type variable bindings.
2727
Optional<PotentialBindings> bestBindings;
28-
llvm::SmallDenseMap<TypeVariableType *, PotentialBindings> cache;
29-
3028
// First, let's collect all of the possible bindings.
3129
for (auto *typeVar : getTypeVariables()) {
3230
if (typeVar->getImpl().hasRepresentativeOrFixed())
3331
continue;
3432

33+
if (Bindings.count(typeVar) > 0)
34+
continue;
35+
3536
if (auto bindings = getPotentialBindings(typeVar))
36-
cache.insert({typeVar, std::move(bindings)});
37+
Bindings.insert({typeVar, std::move(bindings)});
3738
}
3839

3940
// Now let's see if we could infer something for related type
4041
// variables based on other bindings.
4142
for (auto *typeVar : getTypeVariables()) {
42-
auto cachedBindings = cache.find(typeVar);
43-
if (cachedBindings == cache.end())
43+
if (typeVar->getImpl().hasRepresentativeOrFixed())
44+
continue;
45+
46+
auto cachedBindings = Bindings.find(typeVar);
47+
if (cachedBindings == Bindings.end())
4448
continue;
4549

4650
auto &bindings = cachedBindings->getSecond();
@@ -62,8 +66,8 @@ ConstraintSystem::determineBestBindings() {
6266
if (!tv)
6367
continue;
6468

65-
auto relatedBindings = cache.find(tv);
66-
if (relatedBindings == cache.end())
69+
auto relatedBindings = Bindings.find(tv);
70+
if (relatedBindings == Bindings.end())
6771
continue;
6872

6973
for (auto &binding : relatedBindings->getSecond().Bindings) {

lib/Sema/CSSimplify.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1561,7 +1561,6 @@ ConstraintSystem::matchTypesBindTypeVar(
15611561
}
15621562

15631563
assignFixedType(typeVar, type);
1564-
15651564
return getTypeMatchSuccess();
15661565
}
15671566

lib/Sema/ConstraintSystem.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,10 @@ void ConstraintSystem::addTypeVariableConstraintsToWorkList(
232232
constraint);
233233
constraint->setActive(true);
234234
}
235+
236+
// Invalidate pre-computed bindings associated
237+
// with this type variable (if any).
238+
invalidateBindings(typeVar);
235239
}
236240

237241
/// Retrieve a dynamic result signature for the given declaration.

lib/Sema/ConstraintSystem.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,7 @@ class ConstraintSystem {
12131213
/// \param constraint The newly generated constraint.
12141214
void addGeneratedConstraint(Constraint *constraint) {
12151215
generatedConstraints.push_back(constraint);
1216+
CS.invalidateBindings(constraint->getTypeVariables());
12161217
}
12171218

12181219
/// \brief Erase given constraint from the list of generated constraints
@@ -2940,6 +2941,12 @@ class ConstraintSystem {
29402941
}
29412942
};
29422943

2944+
/// Maps type variables to their bindings. Bindings are invalidated
2945+
/// and have to be re-computed if new constraints are introduced or
2946+
/// in relation to a particular set of type variables or type variables
2947+
/// are assigned fixed types or merged together.
2948+
llvm::DenseMap<TypeVariableType *, PotentialBindings> Bindings;
2949+
29432950
Optional<Type> checkTypeOfBinding(TypeVariableType *typeVar, Type type,
29442951
bool *isNilLiteral = nullptr);
29452952
Optional<PotentialBindings> determineBestBindings();
@@ -3228,6 +3235,28 @@ class ConstraintSystem {
32283235
SmallVectorImpl<unsigned> &Ordering,
32293236
SmallVectorImpl<unsigned> &PartitionBeginning);
32303237

3238+
void invalidateBindings(ArrayRef<TypeVariableType *> typeVars) {
3239+
llvm::SmallPtrSet<TypeVariableType *, 8> visitedVars;
3240+
for (auto *typeVar : typeVars) {
3241+
if (typeVar != typeVar->getImpl().getRepresentative(nullptr) ||
3242+
visitedVars.count(typeVar) > 0)
3243+
continue;
3244+
3245+
// If there was no binding, there is no need to disturb
3246+
// other type variables.
3247+
Bindings.erase(typeVar);
3248+
visitedVars.insert(typeVar);
3249+
3250+
for (auto *eqClassVar : CG[typeVar].getEquivalenceClass()) {
3251+
for (auto *adjacentVar : CG[eqClassVar].getAdjacencies()) {
3252+
auto *var = getRepresentative(adjacentVar);
3253+
if (visitedVars.insert(var).second)
3254+
Bindings.erase(var);
3255+
}
3256+
}
3257+
}
3258+
}
3259+
32313260
LLVM_ATTRIBUTE_DEPRECATED(
32323261
void dump() LLVM_ATTRIBUTE_USED,
32333262
"only for use within the debugger");
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %scale-test --begin 1 --end 20 --step 1 --select NumLeafScopes %s
2+
// REQUIRES: OS=macosx
3+
// REQUIRES: asserts
4+
5+
% array_elements = 20
6+
7+
let _ = [
8+
%for i in range(0, N):
9+
${i} : [
10+
%for j in range(array_elements):
11+
"e${j}",
12+
%end
13+
],
14+
%end
15+
]

validation-test/Sema/type_checker_perf/slow/rdar30596744_2.swift.gyb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %scale-test --invert-result --begin 1 --end 5 --step 1 --select NumLeafScopes %s --expected-exit-code 1
1+
// RUN: %scale-test --invert-result --begin 1 --end 4 --step 1 --select NumLeafScopes %s --expected-exit-code 1
22
// REQUIRES: OS=macosx
33
// REQUIRES: asserts
44

0 commit comments

Comments
 (0)