summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/passes/TypeMerging.cpp76
1 files changed, 69 insertions, 7 deletions
diff --git a/src/passes/TypeMerging.cpp b/src/passes/TypeMerging.cpp
index 808076f85..ea1fa7916 100644
--- a/src/passes/TypeMerging.cpp
+++ b/src/passes/TypeMerging.cpp
@@ -152,6 +152,11 @@ struct TypeMerging : public Pass {
enum MergeKind { Supertypes, Siblings };
bool merge(MergeKind kind);
+ // Split a partition into potentially multiple partitions for each
+ // disconnected group of types it contains.
+ std::vector<std::vector<HeapType>>
+ splitSupertypePartition(const std::vector<HeapType>&);
+
CastTypes findCastTypes();
std::vector<HeapType> getPublicChildren(HeapType type);
DFA::State<HeapType> makeDFAState(HeapType type);
@@ -259,6 +264,7 @@ bool TypeMerging::merge(MergeKind kind) {
std::cerr << "\n";
}
};
+
#endif // TYPE_MERGING_DEBUG
// Map each type to its partition in the list.
@@ -361,16 +367,46 @@ bool TypeMerging::merge(MergeKind kind) {
auto refinedPartitions = DFA::refinePartitions(dfa);
#if TYPE_MERGING_DEBUG
+ auto dumpRefinedPartitions = [&]() {
+ size_t i = 0;
+ for (auto& partition : refinedPartitions) {
+ std::cerr << i++ << ": " << print(partition[0]) << "\n";
+ for (size_t j = 1; j < partition.size(); ++j) {
+ std::cerr << " " << print(partition[j]) << "\n";
+ }
+ std::cerr << "\n";
+ }
+ };
std::cerr << "Refined partitions:\n";
- size_t i = 0;
- for (auto& partition : refinedPartitions) {
- std::cerr << i++ << ": " << print(partition[0]) << "\n";
- for (size_t j = 1; j < partition.size(); ++j) {
- std::cerr << " " << print(partition[j]) << "\n";
+ dumpRefinedPartitions();
+#endif
+
+ if (kind == Supertypes) {
+ // It's possible that a partition has been split such that a common ancestor
+ // ended up in one of the new partitions, leaving unrelated types grouped
+ // together in the other new partition. Since we are only supposed to be
+ // merging types into their supertypes, merging such unrelated types would
+ // be unsafe. Post-process the refined partitions to manually split any
+ // partitions containing unrelated types.
+ //
+ // Normally splitting partitions like this would require re-running DFA
+ // minimization afterward, but in this case it is not possible that the
+ // manual splits cause types in any other partition to become
+ // differentiatable. A type and its subtype cannot differ by referring to
+ // different, unrelated types in the same position because then they would
+ // not be in a valid subtype relationship.
+ std::vector<std::vector<HeapType>> newPartitions;
+ for (const auto& partitionTypes : refinedPartitions) {
+ auto split = splitSupertypePartition(partitionTypes);
+ newPartitions.insert(newPartitions.end(), split.begin(), split.end());
}
- std::cerr << "\n";
- }
+ refinedPartitions = newPartitions;
+
+#if TYPE_MERGING_DEBUG
+ std::cerr << "Manually split partitions:\n";
+ dumpRefinedPartitions();
#endif
+ }
// Merge each refined partition into a single type. We should only merge into
// supertypes or siblings because if we try to merge into a subtype then we
@@ -408,6 +444,32 @@ bool TypeMerging::merge(MergeKind kind) {
return merged;
}
+std::vector<std::vector<HeapType>>
+TypeMerging::splitSupertypePartition(const std::vector<HeapType>& types) {
+ if (types.size() == 1) {
+ // Cannot split a partition containing just one type.
+ return {types};
+ }
+ std::unordered_set<HeapType> includedTypes(types.begin(), types.end());
+ std::vector<std::vector<HeapType>> partitions;
+ std::unordered_map<HeapType, Index> partitionIndices;
+ for (auto type : MergeableSupertypesFirst(*this, types)) {
+ auto super = type.getSuperType();
+ if (super && includedTypes.count(*super)) {
+ // We must already have a partition for the supertype we can add to.
+ auto index = partitionIndices.at(*super);
+ partitions[index].push_back(type);
+ partitionIndices[type] = index;
+ } else {
+ // This is a new root type. Create a new partition.
+ auto index = partitions.size();
+ partitions.push_back({type});
+ partitionIndices[type] = index;
+ }
+ }
+ return partitions;
+}
+
CastTypes TypeMerging::findCastTypes() {
ModuleUtils::ParallelFunctionAnalysis<CastTypes> analysis(
*module, [&](Function* func, CastTypes& castTypes) {