Skip to content

Commit 33ff2be

Browse files
authored
Merge pull request #38776 from slavapestov/requirement-machine-property-map-trie
RequirementMachine: Speed up property map lookups with a suffix trie
2 parents 858f78b + 9738d4e commit 33ff2be

11 files changed

+123
-115
lines changed

lib/AST/RequirementMachine/PropertyMap.cpp

Lines changed: 54 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -650,42 +650,19 @@ void PropertyBag::copyPropertiesFrom(const PropertyBag *next,
650650
}
651651
}
652652

653-
/// Look for an property bag corresponding to the given key, returning nullptr
654-
/// if one has not been recorded.
655-
PropertyBag *
656-
PropertyMap::getPropertiesIfPresent(const MutableTerm &key) const {
657-
assert(!key.empty());
658-
659-
for (const auto &props : Map) {
660-
int compare = props->getKey().compare(key, Protos);
661-
if (compare == 0)
662-
return props.get();
663-
if (compare > 0)
664-
return nullptr;
665-
}
666-
667-
return nullptr;
653+
PropertyMap::~PropertyMap() {
654+
Trie.updateHistograms(Context.PropertyTrieHistogram,
655+
Context.PropertyTrieRootHistogram);
656+
clear();
668657
}
669658

670659
/// Look for an property bag corresponding to a suffix of the given key.
671660
///
672661
/// Returns nullptr if no information is known about this key.
673662
PropertyBag *
674663
PropertyMap::lookUpProperties(const MutableTerm &key) const {
675-
if (auto *props = getPropertiesIfPresent(key))
676-
return props;
677-
678-
auto begin = key.begin() + 1;
679-
auto end = key.end();
680-
681-
while (begin != end) {
682-
MutableTerm suffix(begin, end);
683-
684-
if (auto *suffixClass = getPropertiesIfPresent(suffix))
685-
return suffixClass;
686-
687-
++begin;
688-
}
664+
if (auto result = Trie.find(key.rbegin(), key.rend()))
665+
return *result;
689666

690667
return nullptr;
691668
}
@@ -695,17 +672,10 @@ PropertyMap::lookUpProperties(const MutableTerm &key) const {
695672
///
696673
/// This must be called in monotonically non-decreasing key order.
697674
PropertyBag *
698-
PropertyMap::getOrCreateProperties(const MutableTerm &key) {
699-
assert(!key.empty());
700-
701-
if (!Map.empty()) {
702-
const auto &lastEquivClass = Map.back();
703-
int compare = lastEquivClass->getKey().compare(key, Protos);
704-
if (compare == 0)
705-
return lastEquivClass.get();
706-
707-
assert(compare < 0 && "Must record property bags in sorted order");
708-
}
675+
PropertyMap::getOrCreateProperties(Term key) {
676+
auto next = Trie.find(key.rbegin(), key.rend());
677+
if (next && (*next)->getKey() == key)
678+
return *next;
709679

710680
auto *props = new PropertyBag(key);
711681

@@ -730,23 +700,38 @@ PropertyMap::getOrCreateProperties(const MutableTerm &key) {
730700
//
731701
// Since 'A' has no proper suffix with additional properties, the next
732702
// property bag of 'A' is nullptr.
733-
if (auto *next = lookUpProperties(key))
734-
props->copyPropertiesFrom(next, Context);
735-
736-
Map.emplace_back(props);
703+
if (next)
704+
props->copyPropertiesFrom(*next, Context);
705+
706+
Entries.push_back(props);
707+
auto oldProps = Trie.insert(key.rbegin(), key.rend(), props);
708+
if (oldProps) {
709+
llvm::errs() << "Duplicate property map entry for " << key << "\n";
710+
llvm::errs() << "Old:\n";
711+
(*oldProps)->dump(llvm::errs());
712+
llvm::errs() << "\n";
713+
llvm::errs() << "New:\n";
714+
props->dump(llvm::errs());
715+
llvm::errs() << "\n";
716+
abort();
717+
}
737718

738719
return props;
739720
}
740721

741722
void PropertyMap::clear() {
742-
Map.clear();
723+
for (auto *props : Entries)
724+
delete props;
725+
726+
Trie.clear();
727+
Entries.clear();
743728
ConcreteTypeInDomainMap.clear();
744729
}
745730

746731
/// Record a protocol conformance, layout or superclass constraint on the given
747732
/// key. Must be called in monotonically non-decreasing key order.
748733
void PropertyMap::addProperty(
749-
const MutableTerm &key, Symbol property,
734+
Term key, Symbol property,
750735
SmallVectorImpl<std::pair<MutableTerm, MutableTerm>> &inducedRules) {
751736
assert(property.isProperty());
752737
auto *props = getOrCreateProperties(key);
@@ -757,7 +742,7 @@ void PropertyMap::addProperty(
757742
/// For each fully-concrete type, find the shortest term having that concrete type.
758743
/// This is later used by computeConstraintTermForTypeWitness().
759744
void PropertyMap::computeConcreteTypeInDomainMap() {
760-
for (const auto &props : Map) {
745+
for (const auto &props : Entries) {
761746
if (!props->isConcreteType())
762747
continue;
763748

@@ -771,12 +756,8 @@ void PropertyMap::computeConcreteTypeInDomainMap() {
771756
auto concreteTypeKey = std::make_pair(concreteType, domain);
772757

773758
auto found = ConcreteTypeInDomainMap.find(concreteTypeKey);
774-
if (found != ConcreteTypeInDomainMap.end()) {
775-
const auto &otherTerm = found->second;
776-
assert(props->Key.compare(otherTerm, Protos) > 0 &&
777-
"Out-of-order keys?");
759+
if (found != ConcreteTypeInDomainMap.end())
778760
continue;
779-
}
780761

781762
auto inserted = ConcreteTypeInDomainMap.insert(
782763
std::make_pair(concreteTypeKey, props->Key));
@@ -787,7 +768,7 @@ void PropertyMap::computeConcreteTypeInDomainMap() {
787768

788769
void PropertyMap::concretizeNestedTypesFromConcreteParents(
789770
SmallVectorImpl<std::pair<MutableTerm, MutableTerm>> &inducedRules) const {
790-
for (const auto &props : Map) {
771+
for (const auto &props : Entries) {
791772
if (props->getConformsTo().empty())
792773
continue;
793774

@@ -865,7 +846,7 @@ void PropertyMap::concretizeNestedTypesFromConcreteParents(
865846
/// T.[P:B] => U.V
866847
///
867848
void PropertyMap::concretizeNestedTypesFromConcreteParent(
868-
const MutableTerm &key, RequirementKind requirementKind,
849+
Term key, RequirementKind requirementKind,
869850
CanType concreteType, ArrayRef<Term> substitutions,
870851
ArrayRef<const ProtocolDecl *> conformsTo,
871852
llvm::TinyPtrVector<ProtocolConformance *> &conformances,
@@ -928,7 +909,7 @@ void PropertyMap::concretizeNestedTypesFromConcreteParent(
928909
<< " of " << concreteType << " is " << typeWitness << "\n";
929910
}
930911

931-
MutableTerm subjectType = key;
912+
MutableTerm subjectType(key);
932913
subjectType.add(Symbol::forAssociatedType(proto, assocType->getName(),
933914
Context));
934915

@@ -944,7 +925,7 @@ void PropertyMap::concretizeNestedTypesFromConcreteParent(
944925
}
945926

946927
// Add a rule T.[P:A] => T.
947-
constraintType = key;
928+
constraintType = MutableTerm(key);
948929
} else {
949930
constraintType = computeConstraintTermForTypeWitness(
950931
key, concreteType, typeWitness, subjectType,
@@ -985,7 +966,7 @@ void PropertyMap::concretizeNestedTypesFromConcreteParent(
985966
///
986967
/// T.[P:A] => V
987968
MutableTerm PropertyMap::computeConstraintTermForTypeWitness(
988-
const MutableTerm &key, CanType concreteType, CanType typeWitness,
969+
Term key, CanType concreteType, CanType typeWitness,
989970
const MutableTerm &subjectType, ArrayRef<Term> substitutions) const {
990971
if (!typeWitness->hasTypeParameter()) {
991972
// Check if we have a shorter representative we can use.
@@ -994,12 +975,13 @@ MutableTerm PropertyMap::computeConstraintTermForTypeWitness(
994975

995976
auto found = ConcreteTypeInDomainMap.find(concreteTypeKey);
996977
if (found != ConcreteTypeInDomainMap.end()) {
997-
if (found->second != subjectType) {
978+
MutableTerm result(found->second);
979+
if (result != subjectType) {
998980
if (DebugConcretizeNestedTypes) {
999981
llvm::dbgs() << "^^ Type witness can re-use property bag of "
1000982
<< found->second << "\n";
1001983
}
1002-
return found->second;
984+
return result;
1003985
}
1004986
}
1005987
}
@@ -1030,7 +1012,7 @@ MutableTerm PropertyMap::computeConstraintTermForTypeWitness(
10301012

10311013
void PropertyMap::dump(llvm::raw_ostream &out) const {
10321014
out << "Property map: {\n";
1033-
for (const auto &props : Map) {
1015+
for (const auto &props : Entries) {
10341016
out << " ";
10351017
props->dump(out);
10361018
out << "\n";
@@ -1056,7 +1038,11 @@ RewriteSystem::buildPropertyMap(PropertyMap &map,
10561038
unsigned maxDepth) {
10571039
map.clear();
10581040

1059-
std::vector<std::pair<MutableTerm, Symbol>> properties;
1041+
// PropertyMap::addRule() requires that shorter rules are added
1042+
// before longer rules, so that it can perform lookups on suffixes and call
1043+
// PropertyBag::copyPropertiesFrom(). However, we don't have to perform a
1044+
// full sort by term order here; a bucket sort by term length suffices.
1045+
SmallVector<std::vector<std::pair<Term, Symbol>>, 4> properties;
10601046

10611047
for (const auto &rule : Rules) {
10621048
if (rule.isDeleted())
@@ -1076,31 +1062,19 @@ RewriteSystem::buildPropertyMap(PropertyMap &map,
10761062
if (!std::equal(rhs.begin(), rhs.end(), lhs.begin()))
10771063
continue;
10781064

1079-
MutableTerm key(rhs);
1080-
1081-
#ifndef NDEBUG
1082-
assert(!simplify(key) &&
1083-
"Right hand side of a property rule should already be reduced");
1084-
#endif
1085-
1086-
properties.emplace_back(key, property);
1065+
if (rhs.size() >= properties.size())
1066+
properties.resize(rhs.size() + 1);
1067+
properties[rhs.size()].emplace_back(rhs, property);
10871068
}
10881069

1089-
// PropertyMap::addRule() requires that shorter rules are added
1090-
// before longer rules, so that it can perform lookups on suffixes and call
1091-
// PropertyBag::copyPropertiesFrom().
1092-
std::sort(properties.begin(), properties.end(),
1093-
[&](const std::pair<MutableTerm, Symbol> &lhs,
1094-
const std::pair<MutableTerm, Symbol> &rhs) -> bool {
1095-
return lhs.first.compare(rhs.first, Protos) < 0;
1096-
});
1097-
10981070
// Merging multiple superclass or concrete type rules can induce new rules
10991071
// to unify concrete type constructor arguments.
11001072
SmallVector<std::pair<MutableTerm, MutableTerm>, 3> inducedRules;
11011073

1102-
for (auto pair : properties) {
1103-
map.addProperty(pair.first, pair.second, inducedRules);
1074+
for (const auto &bucket : properties) {
1075+
for (auto pair : bucket) {
1076+
map.addProperty(pair.first, pair.second, inducedRules);
1077+
}
11041078
}
11051079

11061080
// We collect terms with fully concrete types so that we can re-use them

lib/AST/RequirementMachine/PropertyMap.h

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
#include "llvm/ADT/SmallVector.h"
2424
#include "llvm/ADT/TinyPtrVector.h"
2525
#include <algorithm>
26-
#include <memory>
2726
#include <vector>
2827

2928
#include "ProtocolGraph.h"
@@ -51,7 +50,7 @@ class PropertyBag {
5150
friend class PropertyMap;
5251

5352
/// The fully reduced term whose properties are recorded in this property bag.
54-
MutableTerm Key;
53+
Term Key;
5554

5655
/// All protocols this type conforms to.
5756
llvm::TinyPtrVector<const ProtocolDecl *> ConformsTo;
@@ -73,7 +72,7 @@ class PropertyBag {
7372
/// ConformsTo list.
7473
llvm::TinyPtrVector<ProtocolConformance *> ConcreteConformances;
7574

76-
explicit PropertyBag(const MutableTerm &key) : Key(key) {}
75+
explicit PropertyBag(Term key) : Key(key) {}
7776

7877
void addProperty(Symbol property,
7978
RewriteContext &ctx,
@@ -88,7 +87,7 @@ class PropertyBag {
8887
PropertyBag &operator=(PropertyBag &&) = delete;
8988

9089
public:
91-
const MutableTerm &getKey() const { return Key; }
90+
Term getKey() const { return Key; }
9291
void dump(llvm::raw_ostream &out) const;
9392

9493
bool hasSuperclassBound() const {
@@ -139,17 +138,17 @@ class PropertyBag {
139138
/// Out-of-line methods are documented in PropertyMap.cpp.
140139
class PropertyMap {
141140
RewriteContext &Context;
142-
std::vector<std::unique_ptr<PropertyBag>> Map;
141+
std::vector<PropertyBag *> Entries;
142+
Trie<PropertyBag *, MatchKind::Longest> Trie;
143143

144144
using ConcreteTypeInDomain = std::pair<CanType, ArrayRef<const ProtocolDecl *>>;
145-
llvm::DenseMap<ConcreteTypeInDomain, MutableTerm> ConcreteTypeInDomainMap;
145+
llvm::DenseMap<ConcreteTypeInDomain, Term> ConcreteTypeInDomainMap;
146146

147147
const ProtocolGraph &Protos;
148148
unsigned DebugConcreteUnification : 1;
149149
unsigned DebugConcretizeNestedTypes : 1;
150150

151-
PropertyBag *getPropertiesIfPresent(const MutableTerm &key) const;
152-
PropertyBag *getOrCreateProperties(const MutableTerm &key);
151+
PropertyBag *getOrCreateProperties(Term key);
153152

154153
PropertyMap(const PropertyMap &) = delete;
155154
PropertyMap(PropertyMap &&) = delete;
@@ -164,12 +163,14 @@ class PropertyMap {
164163
DebugConcretizeNestedTypes = false;
165164
}
166165

166+
~PropertyMap();
167+
167168
PropertyBag *lookUpProperties(const MutableTerm &key) const;
168169

169170
void dump(llvm::raw_ostream &out) const;
170171

171172
void clear();
172-
void addProperty(const MutableTerm &key, Symbol property,
173+
void addProperty(Term key, Symbol property,
173174
SmallVectorImpl<std::pair<MutableTerm, MutableTerm>> &inducedRules);
174175

175176
void computeConcreteTypeInDomainMap();
@@ -178,14 +179,14 @@ class PropertyMap {
178179

179180
private:
180181
void concretizeNestedTypesFromConcreteParent(
181-
const MutableTerm &key, RequirementKind requirementKind,
182+
Term key, RequirementKind requirementKind,
182183
CanType concreteType, ArrayRef<Term> substitutions,
183184
ArrayRef<const ProtocolDecl *> conformsTo,
184185
llvm::TinyPtrVector<ProtocolConformance *> &conformances,
185186
SmallVectorImpl<std::pair<MutableTerm, MutableTerm>> &inducedRules) const;
186187

187188
MutableTerm computeConstraintTermForTypeWitness(
188-
const MutableTerm &key, CanType concreteType, CanType typeWitness,
189+
Term key, CanType concreteType, CanType typeWitness,
189190
const MutableTerm &subjectType, ArrayRef<Term> substitutions) const;
190191
};
191192

lib/AST/RequirementMachine/RewriteContext.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ RewriteContext::RewriteContext(ASTContext &ctx)
2525
SymbolHistogram(Symbol::NumKinds),
2626
TermHistogram(4, /*Start=*/1),
2727
RuleTrieHistogram(16, /*Start=*/1),
28-
RuleTrieRootHistogram(16) {
28+
RuleTrieRootHistogram(16),
29+
PropertyTrieHistogram(16, /*Start=*/1),
30+
PropertyTrieRootHistogram(16) {
2931
}
3032

3133
Term RewriteContext::getTermForType(CanType paramType,
@@ -295,5 +297,9 @@ RewriteContext::~RewriteContext() {
295297
RuleTrieHistogram.dump(llvm::dbgs());
296298
llvm::dbgs() << "\n* Rule trie root fanout:\n";
297299
RuleTrieRootHistogram.dump(llvm::dbgs());
300+
llvm::dbgs() << "\n* Property trie fanout:\n";
301+
PropertyTrieHistogram.dump(llvm::dbgs());
302+
llvm::dbgs() << "\n* Property trie root fanout:\n";
303+
PropertyTrieRootHistogram.dump(llvm::dbgs());
298304
}
299305
}

lib/AST/RequirementMachine/RewriteContext.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ class RewriteContext final {
6060
Histogram TermHistogram;
6161
Histogram RuleTrieHistogram;
6262
Histogram RuleTrieRootHistogram;
63+
Histogram PropertyTrieHistogram;
64+
Histogram PropertyTrieRootHistogram;
6365

6466
explicit RewriteContext(ASTContext &ctx);
6567

0 commit comments

Comments
 (0)