https://github.com/jvoung created https://github.com/llvm/llvm-project/pull/180878
Cache getModeledFields at the DataflowAnalysisContext level (since each of those could have different ModeledFields). Otherwise, the underlying getFieldsFromClassHierarchy is repeated many times and can end up taking 4-10% of the time (compared to 40% for parsing, and 5.3% for querySolver across several benchmarks). Also change the return type to a reference, now that it is not fresh Set each time (though that copy is minor). >From eff6f2b00f5018e4f9eecc1d7ba03eee30cd9f8f Mon Sep 17 00:00:00 2001 From: Jan Voung <[email protected]> Date: Wed, 11 Feb 2026 03:29:12 +0000 Subject: [PATCH] [clang][dataflow] Cache getModeledFields Cache getModeledFields at the DataflowAnalysisContext level (since each of those could have different ModeledFields). Otherwise, the underlying getFieldsFromClassHierarchy is repeated many times and can end up taking 4-10% of the time (compared to 40% for parsing, and 5.3% for querySolver across several benchmarks). Also change the return type to a reference, now that it is not fresh Set each time (though that copy is minor). --- .../FlowSensitive/DataflowAnalysisContext.h | 15 ++++++++++++--- .../FlowSensitive/DataflowAnalysisContext.cpp | 12 +++++++++++- clang/lib/Analysis/FlowSensitive/RecordOps.cpp | 4 ++-- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h index 11042e865c4e6..ebce88a9d9aa3 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h @@ -17,6 +17,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeOrdering.h" #include "clang/Analysis/FlowSensitive/ASTOps.h" #include "clang/Analysis/FlowSensitive/AdornedCFG.h" @@ -207,8 +208,9 @@ class DataflowAnalysisContext { Solver::Result querySolver(llvm::SetVector<const Formula *> Constraints); /// Returns the fields of `Type`, limited to the set of fields modeled by this - /// context. - FieldSet getModeledFields(QualType Type); + /// context. The returned reference is valid for the lifetime of the context, + /// or until `addModeledFields()` is called. + const FieldSet &getModeledFields(QualType Type); /// Returns the names and types of the synthetic fields for the given record /// type. @@ -262,7 +264,11 @@ class DataflowAnalysisContext { /// `Tokens` in the dependency graph. llvm::DenseSet<Atom> collectDependencies(llvm::DenseSet<Atom> Tokens) const; - // Extends the set of modeled field declarations. + /// Computes and returns the fields of `Type`, limited to the set of fields + /// modeled by this context. + FieldSet computeModeledFields(QualType Type); + + /// Extends the set of modeled field declarations. void addModeledFields(const FieldSet &Fields); /// Adds all constraints of the flow condition identified by `Token` and all @@ -329,6 +335,9 @@ class DataflowAnalysisContext { // Fields modeled by environments covered by this context. FieldSet ModeledFields; + // Cache of modeled fields for each type, covered by this context. + llvm::DenseMap<QualType, std::unique_ptr<FieldSet>> CachedModeledFields; + std::unique_ptr<Logger> LogOwner; // If created via flags. std::function<llvm::StringMap<QualType>(QualType)> SyntheticFieldCallback; diff --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp index 6e3a270e6bed6..42b3dafdb9ffa 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" +#include "clang/AST/Type.h" #include "clang/Analysis/FlowSensitive/ASTOps.h" #include "clang/Analysis/FlowSensitive/Formula.h" #include "clang/Analysis/FlowSensitive/Logger.h" @@ -43,7 +44,7 @@ static llvm::cl::opt<std::string> DataflowLog( namespace clang { namespace dataflow { -FieldSet DataflowAnalysisContext::getModeledFields(QualType Type) { +FieldSet DataflowAnalysisContext::computeModeledFields(QualType Type) { // During context-sensitive analysis, a struct may be allocated in one // function, but its field accessed in a function lower in the stack than // the allocation. Since we only collect fields used in the function where @@ -57,8 +58,17 @@ FieldSet DataflowAnalysisContext::getModeledFields(QualType Type) { return llvm::set_intersection(getObjectFields(Type), ModeledFields); } +const FieldSet &DataflowAnalysisContext::getModeledFields(QualType Type) { + std::unique_ptr<FieldSet> &Fields = + CachedModeledFields[Type.getCanonicalType().getUnqualifiedType()]; + if (Fields == nullptr) + Fields = std::make_unique<FieldSet>(computeModeledFields(Type)); + return *Fields; +} + void DataflowAnalysisContext::addModeledFields(const FieldSet &Fields) { ModeledFields.set_union(Fields); + CachedModeledFields.clear(); } StorageLocation &DataflowAnalysisContext::createStorageLocation(QualType Type) { diff --git a/clang/lib/Analysis/FlowSensitive/RecordOps.cpp b/clang/lib/Analysis/FlowSensitive/RecordOps.cpp index 03d6ed8020a0a..767521334b0a2 100644 --- a/clang/lib/Analysis/FlowSensitive/RecordOps.cpp +++ b/clang/lib/Analysis/FlowSensitive/RecordOps.cpp @@ -85,7 +85,7 @@ void copyRecord(RecordStorageLocation &Src, RecordStorageLocation &Dst, // Dst may have children modeled from other derived types than SrcType, e.g. // after casts of Dst to other types derived from DstType. Only copy the // children and synthetic fields present in both Dst and SrcType. - const FieldSet FieldsInSrcType = + const FieldSet &FieldsInSrcType = Env.getDataflowAnalysisContext().getModeledFields(SrcType); for (auto [Field, DstFieldLoc] : Dst.children()) if (const auto *FieldAsFieldDecl = dyn_cast<FieldDecl>(Field); @@ -103,7 +103,7 @@ void copyRecord(RecordStorageLocation &Src, RecordStorageLocation &Dst, // after other casts of Src to those types (likely in different branches, // but without flow-condition-dependent field modeling). Only copy the // children and synthetic fields of Src that are present in DstType. - const FieldSet FieldsInDstType = + const FieldSet &FieldsInDstType = Env.getDataflowAnalysisContext().getModeledFields(DstType); for (auto [Field, SrcFieldLoc] : Src.children()) { if (const auto *FieldAsFieldDecl = dyn_cast<FieldDecl>(Field); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
