Skip to content

Commit 9738d4e

Browse files
committed
RequirementMachine: PropertyMap can use Terms instead of MutableTerms as keys
Also, we don't have to sort rules in term order before adding them to the map; a bucket sort by term length is sufficient.
1 parent 47fc3d8 commit 9738d4e

File tree

6 files changed

+39
-57
lines changed

6 files changed

+39
-57
lines changed

lib/AST/RequirementMachine/PropertyMap.cpp

Lines changed: 27 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -672,14 +672,10 @@ PropertyMap::lookUpProperties(const MutableTerm &key) const {
672672
///
673673
/// This must be called in monotonically non-decreasing key order.
674674
PropertyBag *
675-
PropertyMap::getOrCreateProperties(const MutableTerm &key) {
676-
assert(!key.empty());
677-
678-
if (!Entries.empty()) {
679-
const auto &lastEntry = Entries.back();
680-
if (lastEntry->getKey() == key)
681-
return lastEntry;
682-
}
675+
PropertyMap::getOrCreateProperties(Term key) {
676+
auto next = Trie.find(key.rbegin(), key.rend());
677+
if (next && (*next)->getKey() == key)
678+
return *next;
683679

684680
auto *props = new PropertyBag(key);
685681

@@ -704,12 +700,9 @@ PropertyMap::getOrCreateProperties(const MutableTerm &key) {
704700
//
705701
// Since 'A' has no proper suffix with additional properties, the next
706702
// property bag of 'A' is nullptr.
707-
if (auto *next = lookUpProperties(key))
708-
props->copyPropertiesFrom(next, Context);
703+
if (next)
704+
props->copyPropertiesFrom(*next, Context);
709705

710-
// Here is where we make the assumption that if the new key is not equal to
711-
// the key of the last entry, then it is larger than any key already in the
712-
// map.
713706
Entries.push_back(props);
714707
auto oldProps = Trie.insert(key.rbegin(), key.rend(), props);
715708
if (oldProps) {
@@ -738,7 +731,7 @@ void PropertyMap::clear() {
738731
/// Record a protocol conformance, layout or superclass constraint on the given
739732
/// key. Must be called in monotonically non-decreasing key order.
740733
void PropertyMap::addProperty(
741-
const MutableTerm &key, Symbol property,
734+
Term key, Symbol property,
742735
SmallVectorImpl<std::pair<MutableTerm, MutableTerm>> &inducedRules) {
743736
assert(property.isProperty());
744737
auto *props = getOrCreateProperties(key);
@@ -763,12 +756,8 @@ void PropertyMap::computeConcreteTypeInDomainMap() {
763756
auto concreteTypeKey = std::make_pair(concreteType, domain);
764757

765758
auto found = ConcreteTypeInDomainMap.find(concreteTypeKey);
766-
if (found != ConcreteTypeInDomainMap.end()) {
767-
const auto &otherTerm = found->second;
768-
assert(props->Key.compare(otherTerm, Protos) > 0 &&
769-
"Out-of-order keys?");
759+
if (found != ConcreteTypeInDomainMap.end())
770760
continue;
771-
}
772761

773762
auto inserted = ConcreteTypeInDomainMap.insert(
774763
std::make_pair(concreteTypeKey, props->Key));
@@ -857,7 +846,7 @@ void PropertyMap::concretizeNestedTypesFromConcreteParents(
857846
/// T.[P:B] => U.V
858847
///
859848
void PropertyMap::concretizeNestedTypesFromConcreteParent(
860-
const MutableTerm &key, RequirementKind requirementKind,
849+
Term key, RequirementKind requirementKind,
861850
CanType concreteType, ArrayRef<Term> substitutions,
862851
ArrayRef<const ProtocolDecl *> conformsTo,
863852
llvm::TinyPtrVector<ProtocolConformance *> &conformances,
@@ -920,7 +909,7 @@ void PropertyMap::concretizeNestedTypesFromConcreteParent(
920909
<< " of " << concreteType << " is " << typeWitness << "\n";
921910
}
922911

923-
MutableTerm subjectType = key;
912+
MutableTerm subjectType(key);
924913
subjectType.add(Symbol::forAssociatedType(proto, assocType->getName(),
925914
Context));
926915

@@ -936,7 +925,7 @@ void PropertyMap::concretizeNestedTypesFromConcreteParent(
936925
}
937926

938927
// Add a rule T.[P:A] => T.
939-
constraintType = key;
928+
constraintType = MutableTerm(key);
940929
} else {
941930
constraintType = computeConstraintTermForTypeWitness(
942931
key, concreteType, typeWitness, subjectType,
@@ -977,7 +966,7 @@ void PropertyMap::concretizeNestedTypesFromConcreteParent(
977966
///
978967
/// T.[P:A] => V
979968
MutableTerm PropertyMap::computeConstraintTermForTypeWitness(
980-
const MutableTerm &key, CanType concreteType, CanType typeWitness,
969+
Term key, CanType concreteType, CanType typeWitness,
981970
const MutableTerm &subjectType, ArrayRef<Term> substitutions) const {
982971
if (!typeWitness->hasTypeParameter()) {
983972
// Check if we have a shorter representative we can use.
@@ -986,12 +975,13 @@ MutableTerm PropertyMap::computeConstraintTermForTypeWitness(
986975

987976
auto found = ConcreteTypeInDomainMap.find(concreteTypeKey);
988977
if (found != ConcreteTypeInDomainMap.end()) {
989-
if (found->second != subjectType) {
978+
MutableTerm result(found->second);
979+
if (result != subjectType) {
990980
if (DebugConcretizeNestedTypes) {
991981
llvm::dbgs() << "^^ Type witness can re-use property bag of "
992982
<< found->second << "\n";
993983
}
994-
return found->second;
984+
return result;
995985
}
996986
}
997987
}
@@ -1048,7 +1038,11 @@ RewriteSystem::buildPropertyMap(PropertyMap &map,
10481038
unsigned maxDepth) {
10491039
map.clear();
10501040

1051-
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;
10521046

10531047
for (const auto &rule : Rules) {
10541048
if (rule.isDeleted())
@@ -1068,31 +1062,19 @@ RewriteSystem::buildPropertyMap(PropertyMap &map,
10681062
if (!std::equal(rhs.begin(), rhs.end(), lhs.begin()))
10691063
continue;
10701064

1071-
MutableTerm key(rhs);
1072-
1073-
#ifndef NDEBUG
1074-
assert(!simplify(key) &&
1075-
"Right hand side of a property rule should already be reduced");
1076-
#endif
1077-
1078-
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);
10791068
}
10801069

1081-
// PropertyMap::addRule() requires that shorter rules are added
1082-
// before longer rules, so that it can perform lookups on suffixes and call
1083-
// PropertyBag::copyPropertiesFrom().
1084-
std::sort(properties.begin(), properties.end(),
1085-
[&](const std::pair<MutableTerm, Symbol> &lhs,
1086-
const std::pair<MutableTerm, Symbol> &rhs) -> bool {
1087-
return lhs.first.compare(rhs.first, Protos) < 0;
1088-
});
1089-
10901070
// Merging multiple superclass or concrete type rules can induce new rules
10911071
// to unify concrete type constructor arguments.
10921072
SmallVector<std::pair<MutableTerm, MutableTerm>, 3> inducedRules;
10931073

1094-
for (auto pair : properties) {
1095-
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+
}
10961078
}
10971079

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

lib/AST/RequirementMachine/PropertyMap.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class PropertyBag {
5050
friend class PropertyMap;
5151

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

5555
/// All protocols this type conforms to.
5656
llvm::TinyPtrVector<const ProtocolDecl *> ConformsTo;
@@ -72,7 +72,7 @@ class PropertyBag {
7272
/// ConformsTo list.
7373
llvm::TinyPtrVector<ProtocolConformance *> ConcreteConformances;
7474

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

7777
void addProperty(Symbol property,
7878
RewriteContext &ctx,
@@ -87,7 +87,7 @@ class PropertyBag {
8787
PropertyBag &operator=(PropertyBag &&) = delete;
8888

8989
public:
90-
const MutableTerm &getKey() const { return Key; }
90+
Term getKey() const { return Key; }
9191
void dump(llvm::raw_ostream &out) const;
9292

9393
bool hasSuperclassBound() const {
@@ -142,13 +142,13 @@ class PropertyMap {
142142
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 *getOrCreateProperties(const MutableTerm &key);
151+
PropertyBag *getOrCreateProperties(Term key);
152152

153153
PropertyMap(const PropertyMap &) = delete;
154154
PropertyMap(PropertyMap &&) = delete;
@@ -170,7 +170,7 @@ class PropertyMap {
170170
void dump(llvm::raw_ostream &out) const;
171171

172172
void clear();
173-
void addProperty(const MutableTerm &key, Symbol property,
173+
void addProperty(Term key, Symbol property,
174174
SmallVectorImpl<std::pair<MutableTerm, MutableTerm>> &inducedRules);
175175

176176
void computeConcreteTypeInDomainMap();
@@ -179,14 +179,14 @@ class PropertyMap {
179179

180180
private:
181181
void concretizeNestedTypesFromConcreteParent(
182-
const MutableTerm &key, RequirementKind requirementKind,
182+
Term key, RequirementKind requirementKind,
183183
CanType concreteType, ArrayRef<Term> substitutions,
184184
ArrayRef<const ProtocolDecl *> conformsTo,
185185
llvm::TinyPtrVector<ProtocolConformance *> &conformances,
186186
SmallVectorImpl<std::pair<MutableTerm, MutableTerm>> &inducedRules) const;
187187

188188
MutableTerm computeConstraintTermForTypeWitness(
189-
const MutableTerm &key, CanType concreteType, CanType typeWitness,
189+
Term key, CanType concreteType, CanType typeWitness,
190190
const MutableTerm &subjectType, ArrayRef<Term> substitutions) const;
191191
};
192192

test/Generics/rdar79564324.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,6 @@ public func test<T : P>(_ t: T) where T == T.A {
3535
// CHECK-NEXT: }
3636
// CHECK-NEXT: Property map: {
3737
// CHECK-NEXT: [P:A] => { conforms_to: [P] }
38-
// CHECK-NEXT: τ_0_0 => { conforms_to: [P] }
3938
// CHECK-NEXT: τ_0_1 => { conforms_to: [P] }
39+
// CHECK-NEXT: τ_0_0 => { conforms_to: [P] }
4040
// CHECK-NEXT: }

test/Generics/unify_associated_types.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ struct MergeTest<G : P1a & P2a> {}
2929
// CHECK: - [P1a&P2a:T].[P1:X] => [P1a&P2a:T].[P1&P2:X]
3030
// CHECK: }
3131
// CHECK: Property map: {
32-
// CHECK: [P1a&P2a:T] => { conforms_to: [P1 P2] }
3332
// CHECK: [P1a:T] => { conforms_to: [P1] }
3433
// CHECK: [P2a:T] => { conforms_to: [P2] }
3534
// CHECK: τ_0_0 => { conforms_to: [P1a P2a] }
35+
// CHECK: [P1a&P2a:T] => { conforms_to: [P1 P2] }
3636
// CHECK: }
3737
// CHECK: }
3838

test/Generics/unify_superclass_types_2.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,6 @@ func unifySuperclassTest<T : P1 & P2>(_: T) {
4242
// CHECK-NEXT: [P2:X] => { layout: _NativeClass superclass: [superclass: Generic<τ_0_0, String, τ_0_1> with <[P2:A2], [P2:B2]>] }
4343
// CHECK-NEXT: τ_0_0 => { conforms_to: [P1 P2] }
4444
// CHECK-NEXT: τ_0_0.[P1&P2:X] => { layout: _NativeClass superclass: [superclass: Generic<Int, τ_0_0, τ_0_1> with <τ_0_0.[P1:A1], τ_0_0.[P1:B1]>] }
45-
// CHECK-NEXT: τ_0_0.[P1:A1] => { concrete_type: [concrete: String] }
4645
// CHECK-NEXT: τ_0_0.[P2:A2] => { concrete_type: [concrete: Int] }
46+
// CHECK-NEXT: τ_0_0.[P1:A1] => { concrete_type: [concrete: String] }
4747
// CHECK-NEXT: }

test/Generics/unify_superclass_types_3.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,6 @@ func unifySuperclassTest<T : P1 & P2>(_: T) {
4444
// CHECK-NEXT: [P2:X] => { layout: _NativeClass superclass: [superclass: Generic<τ_0_0, String, τ_0_1> with <[P2:A2], [P2:B2]>] }
4545
// CHECK-NEXT: τ_0_0 => { conforms_to: [P1 P2] }
4646
// CHECK-NEXT: τ_0_0.[P1&P2:X] => { layout: _NativeClass superclass: [superclass: Derived<τ_0_0, τ_0_1> with <τ_0_0.[P1:A1], τ_0_0.[P1:B1]>] }
47-
// CHECK-NEXT: τ_0_0.[P1:A1] => { concrete_type: [concrete: String] }
4847
// CHECK-NEXT: τ_0_0.[P2:A2] => { concrete_type: [concrete: Int] }
48+
// CHECK-NEXT: τ_0_0.[P1:A1] => { concrete_type: [concrete: String] }
4949
// CHECK-NEXT: }

0 commit comments

Comments
 (0)