@@ -2013,6 +2013,66 @@ static Constraint *tryOptimizeGenericDisjunction(
2013
2013
llvm_unreachable (" covered switch" );
2014
2014
}
2015
2015
2016
+ // / Populates the \c found vector with the indices of the given constraints
2017
+ // / that have a matching type to an existing operator binding elsewhere in
2018
+ // / the expression.
2019
+ // /
2020
+ // / Operator bindings that have a matching type to an existing binding
2021
+ // / are attempted first by the solver because it's very common to chain
2022
+ // / operators of the same type together.
2023
+ static void existingOperatorBindingsForDisjunction (ConstraintSystem &CS,
2024
+ ArrayRef<Constraint *> constraints,
2025
+ SmallVectorImpl<unsigned > &found) {
2026
+ auto *choice = constraints.front ();
2027
+ if (choice->getKind () != ConstraintKind::BindOverload)
2028
+ return ;
2029
+
2030
+ auto overload = choice->getOverloadChoice ();
2031
+ if (!overload.isDecl ())
2032
+ return ;
2033
+ auto decl = overload.getDecl ();
2034
+ if (!decl->isOperator ())
2035
+ return ;
2036
+
2037
+ // For concrete operators, consider overloads that have the same type as
2038
+ // an existing binding, because it's very common to write mixed operator
2039
+ // expressions where all operands have the same type, e.g. `(x + 10) / 2`.
2040
+ // For generic operators, only favor an exact overload that has already
2041
+ // been bound, because mixed operator expressions are far less common, and
2042
+ // computing generic canonical types is expensive.
2043
+ SmallSet<CanType, 4 > concreteTypesFound;
2044
+ SmallSet<ValueDecl *, 4 > genericDeclsFound;
2045
+ for (auto overload : CS.getResolvedOverloads ()) {
2046
+ auto resolved = overload.second ;
2047
+ if (!resolved.choice .isDecl ())
2048
+ continue ;
2049
+
2050
+ auto representativeDecl = resolved.choice .getDecl ();
2051
+ if (!representativeDecl->isOperator ())
2052
+ continue ;
2053
+
2054
+ auto interfaceType = representativeDecl->getInterfaceType ();
2055
+ if (interfaceType->is <GenericFunctionType>()) {
2056
+ genericDeclsFound.insert (representativeDecl);
2057
+ } else {
2058
+ concreteTypesFound.insert (interfaceType->getCanonicalType ());
2059
+ }
2060
+ }
2061
+
2062
+ for (auto index : indices (constraints)) {
2063
+ auto *constraint = constraints[index];
2064
+ if (constraint->isFavored ())
2065
+ continue ;
2066
+
2067
+ auto *decl = constraint->getOverloadChoice ().getDecl ();
2068
+ auto interfaceType = decl->getInterfaceType ();
2069
+ bool isGeneric = interfaceType->is <GenericFunctionType>();
2070
+ if ((isGeneric && genericDeclsFound.count (decl)) ||
2071
+ (!isGeneric && concreteTypesFound.count (interfaceType->getCanonicalType ())))
2072
+ found.push_back (index);
2073
+ }
2074
+ }
2075
+
2016
2076
void ConstraintSystem::partitionDisjunction (
2017
2077
ArrayRef<Constraint *> Choices, SmallVectorImpl<unsigned > &Ordering,
2018
2078
SmallVectorImpl<unsigned > &PartitionBeginning) {
@@ -2042,12 +2102,18 @@ void ConstraintSystem::partitionDisjunction(
2042
2102
2043
2103
// First collect some things that we'll generally put near the beginning or
2044
2104
// end of the partitioning.
2045
-
2046
2105
SmallVector<unsigned , 4 > favored;
2106
+ SmallVector<unsigned , 4 > everythingElse;
2047
2107
SmallVector<unsigned , 4 > simdOperators;
2048
2108
SmallVector<unsigned , 4 > disabled;
2049
2109
SmallVector<unsigned , 4 > unavailable;
2050
2110
2111
+ // Add existing operator bindings to the main partition first. This often
2112
+ // helps the solver find a solution fast.
2113
+ existingOperatorBindingsForDisjunction (*this , Choices, everythingElse);
2114
+ for (auto index : everythingElse)
2115
+ taken.insert (Choices[index]);
2116
+
2051
2117
// First collect disabled and favored constraints.
2052
2118
forEachChoice (Choices, [&](unsigned index, Constraint *constraint) -> bool {
2053
2119
if (constraint->isDisabled ()) {
@@ -2107,7 +2173,6 @@ void ConstraintSystem::partitionDisjunction(
2107
2173
}
2108
2174
};
2109
2175
2110
- SmallVector<unsigned , 4 > everythingElse;
2111
2176
// Gather the remaining options.
2112
2177
forEachChoice (Choices, [&](unsigned index, Constraint *constraint) -> bool {
2113
2178
everythingElse.push_back (index);
@@ -2134,13 +2199,34 @@ Constraint *ConstraintSystem::selectDisjunction() {
2134
2199
if (auto *disjunction = selectBestBindingDisjunction (*this , disjunctions))
2135
2200
return disjunction;
2136
2201
2137
- // Pick the disjunction with the smallest number of active choices.
2138
- auto minDisjunction =
2139
- std::min_element (disjunctions.begin (), disjunctions.end (),
2140
- [&](Constraint *first, Constraint *second) -> bool {
2141
- return first->countActiveNestedConstraints () <
2142
- second->countActiveNestedConstraints ();
2143
- });
2202
+ // Pick the disjunction with the smallest number of favored, then active choices.
2203
+ auto cs = this ;
2204
+ auto minDisjunction = std::min_element (disjunctions.begin (), disjunctions.end (),
2205
+ [&](Constraint *first, Constraint *second) -> bool {
2206
+ unsigned firstFavored = first->countFavoredNestedConstraints ();
2207
+ unsigned secondFavored = second->countFavoredNestedConstraints ();
2208
+
2209
+ if (!isOperatorBindOverload (first->getNestedConstraints ().front ()) ||
2210
+ !isOperatorBindOverload (second->getNestedConstraints ().front ()))
2211
+ return first->countActiveNestedConstraints () < second->countActiveNestedConstraints ();
2212
+
2213
+ if (firstFavored == secondFavored) {
2214
+ // Look for additional choices to favor
2215
+ SmallVector<unsigned , 4 > firstExisting;
2216
+ SmallVector<unsigned , 4 > secondExisting;
2217
+
2218
+ existingOperatorBindingsForDisjunction (*cs, first->getNestedConstraints (), firstExisting);
2219
+ firstFavored = firstExisting.size () ? firstExisting.size () : first->countActiveNestedConstraints ();
2220
+ existingOperatorBindingsForDisjunction (*cs, second->getNestedConstraints (), secondExisting);
2221
+ secondFavored = secondExisting.size () ? secondExisting.size () : second->countActiveNestedConstraints ();
2222
+
2223
+ return firstFavored < secondFavored;
2224
+ }
2225
+
2226
+ firstFavored = firstFavored ? firstFavored : first->countActiveNestedConstraints ();
2227
+ secondFavored = secondFavored ? secondFavored : second->countActiveNestedConstraints ();
2228
+ return firstFavored < secondFavored;
2229
+ });
2144
2230
2145
2231
if (minDisjunction != disjunctions.end ())
2146
2232
return *minDisjunction;
0 commit comments