@@ -2013,6 +2013,66 @@ static Constraint *tryOptimizeGenericDisjunction(
20132013 llvm_unreachable (" covered switch" );
20142014}
20152015
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+
20162076void ConstraintSystem::partitionDisjunction (
20172077 ArrayRef<Constraint *> Choices, SmallVectorImpl<unsigned > &Ordering,
20182078 SmallVectorImpl<unsigned > &PartitionBeginning) {
@@ -2042,12 +2102,18 @@ void ConstraintSystem::partitionDisjunction(
20422102
20432103 // First collect some things that we'll generally put near the beginning or
20442104 // end of the partitioning.
2045-
20462105 SmallVector<unsigned , 4 > favored;
2106+ SmallVector<unsigned , 4 > everythingElse;
20472107 SmallVector<unsigned , 4 > simdOperators;
20482108 SmallVector<unsigned , 4 > disabled;
20492109 SmallVector<unsigned , 4 > unavailable;
20502110
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+
20512117 // First collect disabled and favored constraints.
20522118 forEachChoice (Choices, [&](unsigned index, Constraint *constraint) -> bool {
20532119 if (constraint->isDisabled ()) {
@@ -2107,7 +2173,6 @@ void ConstraintSystem::partitionDisjunction(
21072173 }
21082174 };
21092175
2110- SmallVector<unsigned , 4 > everythingElse;
21112176 // Gather the remaining options.
21122177 forEachChoice (Choices, [&](unsigned index, Constraint *constraint) -> bool {
21132178 everythingElse.push_back (index);
@@ -2134,13 +2199,34 @@ Constraint *ConstraintSystem::selectDisjunction() {
21342199 if (auto *disjunction = selectBestBindingDisjunction (*this , disjunctions))
21352200 return disjunction;
21362201
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+ });
21442230
21452231 if (minDisjunction != disjunctions.end ())
21462232 return *minDisjunction;
0 commit comments