Skip to content

Commit 07117da

Browse files
committed
Cache satisfaction of ConceptIdConstraint.
We substitute into concept ids for diagnostics purposes. However, most of the time this happen in SFINEA context and impact performance noticeably.
1 parent 007cc87 commit 07117da

File tree

1 file changed

+74
-30
lines changed

1 file changed

+74
-30
lines changed

clang/lib/Sema/SemaConcept.cpp

Lines changed: 74 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,10 @@ class ConstraintSatisfactionChecker {
462462
ExprResult Evaluate(const FoldExpandedConstraint &Constraint,
463463
const MultiLevelTemplateArgumentList &MLTAL);
464464

465+
ExprResult EvaluateSlow(const ConceptIdConstraint &Constraint,
466+
const MultiLevelTemplateArgumentList &MLTAL,
467+
unsigned int Size);
468+
465469
ExprResult Evaluate(const ConceptIdConstraint &Constraint,
466470
const MultiLevelTemplateArgumentList &MLTAL);
467471

@@ -855,35 +859,12 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
855859
return Out;
856860
}
857861

858-
ExprResult ConstraintSatisfactionChecker::Evaluate(
862+
ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
859863
const ConceptIdConstraint &Constraint,
860-
const MultiLevelTemplateArgumentList &MLTAL) {
861-
864+
const MultiLevelTemplateArgumentList &MLTAL,
865+
unsigned Size) {
862866
const ConceptReference *ConceptId = Constraint.getConceptId();
863867

864-
std::optional<Sema::InstantiatingTemplate> InstTemplate;
865-
InstTemplate.emplace(S, ConceptId->getBeginLoc(),
866-
Sema::InstantiatingTemplate::ConstraintsCheck{},
867-
ConceptId->getNamedConcept(), MLTAL.getInnermost(),
868-
Constraint.getSourceRange());
869-
870-
unsigned Size = Satisfaction.Details.size();
871-
872-
ExprResult E = Evaluate(Constraint.getNormalizedConstraint(), MLTAL);
873-
874-
if (!E.isUsable()) {
875-
Satisfaction.Details.insert(Satisfaction.Details.begin() + Size, ConceptId);
876-
return E;
877-
}
878-
879-
// ConceptIdConstraint is only relevant for diagnostics,
880-
// so if the normalized constraint is satisfied, we should not
881-
// substitute into the constraint.
882-
if (Satisfaction.IsSatisfied)
883-
return E;
884-
885-
// TODO: We might want to cache the substitution of concept id constraints
886-
// as it can be slow in the SFINAE case.
887868
llvm::SmallVector<TemplateArgument> SubstitutedOuterMost;
888869
std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
889870
SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOuterMost);
@@ -903,7 +884,7 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
903884
const ASTTemplateArgumentListInfo *Ori =
904885
ConceptId->getTemplateArgsAsWritten();
905886
TemplateDeductionInfo Info(TemplateNameLoc);
906-
InstTemplate.emplace(
887+
Sema::InstantiatingTemplate _(
907888
S, TemplateNameLoc, Sema::InstantiatingTemplate::ConstraintSubstitution{},
908889
const_cast<NamedDecl *>(Template), Info, Constraint.getSourceRange());
909890

@@ -926,8 +907,8 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
926907
Satisfaction.Details.insert(
927908
Satisfaction.Details.begin() + Size,
928909
new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
929-
SubstDiag.first,
930-
allocateStringFromConceptDiagnostic(S, SubstDiag.second)});
910+
SubstDiag.first,
911+
allocateStringFromConceptDiagnostic(S, SubstDiag.second)});
931912
return ExprError();
932913
}
933914

@@ -940,7 +921,7 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
940921
/*DoCheckConstraintSatisfaction=*/false);
941922

942923
if (SubstitutedConceptId.isInvalid() || Trap.hasErrorOccurred())
943-
return E;
924+
return ExprError();
944925

945926
if (Size != Satisfaction.Details.size()) {
946927
Satisfaction.Details.insert(
@@ -952,6 +933,69 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
952933
return SubstitutedConceptId;
953934
}
954935

936+
ExprResult ConstraintSatisfactionChecker::Evaluate(
937+
const ConceptIdConstraint &Constraint,
938+
const MultiLevelTemplateArgumentList &MLTAL) {
939+
940+
const ConceptReference *ConceptId = Constraint.getConceptId();
941+
942+
UnsignedOrNone OuterPackSubstIndex =
943+
Constraint.getPackSubstitutionIndex()
944+
? Constraint.getPackSubstitutionIndex()
945+
: PackSubstitutionIndex;
946+
947+
Sema::InstantiatingTemplate _ (S, ConceptId->getBeginLoc(),
948+
Sema::InstantiatingTemplate::ConstraintsCheck{},
949+
ConceptId->getNamedConcept(), MLTAL.getInnermost(),
950+
Constraint.getSourceRange());
951+
952+
unsigned Size = Satisfaction.Details.size();
953+
954+
ExprResult E = Evaluate(Constraint.getNormalizedConstraint(), MLTAL);
955+
956+
if (!E.isUsable()) {
957+
Satisfaction.Details.insert(Satisfaction.Details.begin() + Size, ConceptId);
958+
return E;
959+
}
960+
961+
// ConceptIdConstraint is only relevant for diagnostics,
962+
// so if the normalized constraint is satisfied, we should not
963+
// substitute into the constraint.
964+
if (Satisfaction.IsSatisfied)
965+
return E;
966+
967+
llvm::FoldingSetNodeID ID;
968+
ID.AddPointer(Constraint.getConceptId());
969+
ID.AddInteger(OuterPackSubstIndex.toInternalRepresentation());
970+
ID.AddBoolean(Constraint.hasParameterMapping());
971+
HashParameterMapping(S, MLTAL, ID, OuterPackSubstIndex)
972+
.VisitConstraint(Constraint);
973+
974+
975+
if (auto Iter = S.UnsubstitutedConstraintSatisfactionCache.find(ID);
976+
Iter != S.UnsubstitutedConstraintSatisfactionCache.end()) {
977+
978+
auto &Cached = Iter->second.Satisfaction;
979+
Satisfaction.ContainsErrors = Cached.ContainsErrors;
980+
Satisfaction.IsSatisfied = Cached.IsSatisfied;
981+
Satisfaction.Details.insert(Satisfaction.Details.begin() + Size,
982+
Cached.Details.begin(), Cached.Details.end());
983+
return Iter->second.SubstExpr;
984+
}
985+
986+
ExprResult CE = EvaluateSlow(Constraint, MLTAL, Size);
987+
if(CE.isInvalid())
988+
return E;
989+
UnsubstitutedConstraintSatisfactionCacheResult Cache;
990+
Cache.Satisfaction.ContainsErrors = Satisfaction.ContainsErrors;
991+
Cache.Satisfaction.IsSatisfied = Satisfaction.IsSatisfied;
992+
std::copy(Satisfaction.Details.begin() + Size, Satisfaction.Details.end(),
993+
std::back_inserter(Cache.Satisfaction.Details));
994+
Cache.SubstExpr = CE;
995+
S.UnsubstitutedConstraintSatisfactionCache.insert({ID, std::move(Cache)});
996+
return CE;
997+
}
998+
955999
ExprResult ConstraintSatisfactionChecker::Evaluate(
9561000
const CompoundConstraint &Constraint,
9571001
const MultiLevelTemplateArgumentList &MLTAL) {

0 commit comments

Comments
 (0)