https://github.com/necto updated https://github.com/llvm/llvm-project/pull/163341
>From 164cd40a4948a5e0e0095d86158e4bfc288d6a5b Mon Sep 17 00:00:00 2001 From: Arseniy Zaostrovnykh <[email protected]> Date: Tue, 14 Oct 2025 10:13:15 +0200 Subject: [PATCH 1/3] [clang][analyzer] Add SyntaxRunningTime per-entry-point metric Per-entry-point metrics are captured during the path-sensitive analysis time. For that reason, it is not trivial to add the syntax-only analysis time as it runs in a separate stage. Luckily syntax-only analysis is done before path-senstivie analysis. I use the function summary field to keep the syntax-only anlaysis time once syntax analysis is done, and then forward it to the per-EP metrics snapshot during the path-sensitive analysis. -- CPP-7099 --- .../Core/PathSensitive/FunctionSummary.h | 8 ++++ .../Frontend/AnalysisConsumer.cpp | 43 +++++++++++++++++++ .../analyzer-stats/entry-point-stats.cpp | 2 + 3 files changed, 53 insertions(+) diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h index 761395260a0cf..db4aec7c84754 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h @@ -48,6 +48,9 @@ class FunctionSummariesTy { /// The number of times the function has been inlined. unsigned TimesInlined : 32; + /// Running time for syntax-based AST analysis in milliseconds. + std::optional<unsigned> SyntaxRunningTime = std::nullopt; + FunctionSummary() : TotalBasicBlocks(0), InlineChecked(0), MayInline(0), TimesInlined(0) {} @@ -69,6 +72,11 @@ class FunctionSummariesTy { return I; } + FunctionSummary const *findSummary(const Decl *D) const { + auto I = Map.find(D); + return I == Map.end() ? nullptr : &I->second; + } + void markMayInline(const Decl *D) { MapTy::iterator I = findOrInsertSummary(D); I->second.InlineChecked = 1; diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 4efde59aab763..1775280fa7e1e 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -721,6 +721,7 @@ AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) { } static UnsignedEPStat PathRunningTime("PathRunningTime"); +static UnsignedEPStat SyntaxRunningTime("SyntaxRunningTime"); void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode, ExprEngine::InliningModes IMode, @@ -759,6 +760,8 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode, SyntaxCheckTimer->stopTimer(); llvm::TimeRecord CheckerEndTime = SyntaxCheckTimer->getTotalTime(); CheckerEndTime -= CheckerStartTime; + FunctionSummaries.findOrInsertSummary(D)->second.SyntaxRunningTime = + std::lround(CheckerEndTime.getWallTime() * 1000); DisplayTime(CheckerEndTime); if (AnalyzerTimers && ShouldClearTimersToPreventDisplayingThem) { AnalyzerTimers->clear(); @@ -776,6 +779,36 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode, } } +namespace { +template <typename DeclT> +static clang::Decl *preferDefinitionImpl(clang::Decl *D) { + if (auto *X = dyn_cast<DeclT>(D)) + if (auto *Def = X->getDefinition()) + return Def; + return D; +} + +template <> clang::Decl *preferDefinitionImpl<ObjCMethodDecl>(clang::Decl *D) { + if (const auto *X = dyn_cast<ObjCMethodDecl>(D)) { + for (auto *I : X->redecls()) + if (I->hasBody()) + return I; + } + return D; +} + +static Decl *getDefinitionOrCanonicalDecl(Decl *D) { + assert(D); + D = D->getCanonicalDecl(); + D = preferDefinitionImpl<VarDecl>(D); + D = preferDefinitionImpl<FunctionDecl>(D); + D = preferDefinitionImpl<TagDecl>(D); + D = preferDefinitionImpl<ObjCMethodDecl>(D); + assert(D); + return D; +} +} // namespace + //===----------------------------------------------------------------------===// // Path-sensitive checking. //===----------------------------------------------------------------------===// @@ -792,6 +825,16 @@ void AnalysisConsumer::RunPathSensitiveChecks(Decl *D, if (!Mgr->getAnalysisDeclContext(D)->getAnalysis<RelaxedLiveVariables>()) return; + const Decl *DefDecl = getDefinitionOrCanonicalDecl(D); + + // Get the SyntaxRunningTime from the function summary, because it is computed + // during the AM_Syntax analysis, which is done at a different point in time + // and in different order, but always before AM_Path. + if (const auto *Summary = FunctionSummaries.findSummary(DefDecl); + Summary && Summary->SyntaxRunningTime.has_value()) { + SyntaxRunningTime.set(*Summary->SyntaxRunningTime); + } + ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode); // Execute the worklist algorithm. diff --git a/clang/test/Analysis/analyzer-stats/entry-point-stats.cpp b/clang/test/Analysis/analyzer-stats/entry-point-stats.cpp index 2a0caad5950ec..c0c13d88a278d 100644 --- a/clang/test/Analysis/analyzer-stats/entry-point-stats.cpp +++ b/clang/test/Analysis/analyzer-stats/entry-point-stats.cpp @@ -9,6 +9,7 @@ // CHECK-NEXT: "File": "{{.*}}entry-point-stats.cpp", // CHECK-NEXT: "DebugName": "fib(unsigned int)", // CHECK-NEXT: "PathRunningTime": "{{[0-9]+}}", +// CHECK-NEXT: "SyntaxRunningTime": "{{[0-9]+}}", // CHECK-NEXT: "MaxBugClassSize": "{{[0-9]+}}", // CHECK-NEXT: "MaxCFGSize": "{{[0-9]+}}", // CHECK-NEXT: "MaxQueueSize": "{{[0-9]+}}", @@ -46,6 +47,7 @@ // CHECK-NEXT: "File": "{{.*}}entry-point-stats.cpp", // CHECK-NEXT: "DebugName": "main(int, char **)", // CHECK-NEXT: "PathRunningTime": "{{[0-9]+}}", +// CHECK-NEXT: "SyntaxRunningTime": "{{[0-9]+}}", // CHECK-NEXT: "MaxBugClassSize": "{{[0-9]+}}", // CHECK-NEXT: "MaxCFGSize": "{{[0-9]+}}", // CHECK-NEXT: "MaxQueueSize": "{{[0-9]+}}", >From ceb77a73c8f46ee97c205f8b643469fc554a923d Mon Sep 17 00:00:00 2001 From: Arseniy Zaostrovnykh <[email protected]> Date: Tue, 14 Oct 2025 11:06:33 +0200 Subject: [PATCH 2/3] [NFC] Remove redundant anonymous namespace --- clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 1775280fa7e1e..0e1679f5c7e04 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -779,7 +779,6 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode, } } -namespace { template <typename DeclT> static clang::Decl *preferDefinitionImpl(clang::Decl *D) { if (auto *X = dyn_cast<DeclT>(D)) @@ -807,7 +806,6 @@ static Decl *getDefinitionOrCanonicalDecl(Decl *D) { assert(D); return D; } -} // namespace //===----------------------------------------------------------------------===// // Path-sensitive checking. >From 13b4f6918a746e54e4484bfe5ab850ed8db5e9c9 Mon Sep 17 00:00:00 2001 From: Arseniy Zaostrovnykh <[email protected]> Date: Tue, 14 Oct 2025 11:31:33 +0200 Subject: [PATCH 3/3] Use the same defining declaration of D as getAnalysisDeclContext --- .../Frontend/AnalysisConsumer.cpp | 35 +++---------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 0e1679f5c7e04..62513357a21a8 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -779,34 +779,6 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode, } } -template <typename DeclT> -static clang::Decl *preferDefinitionImpl(clang::Decl *D) { - if (auto *X = dyn_cast<DeclT>(D)) - if (auto *Def = X->getDefinition()) - return Def; - return D; -} - -template <> clang::Decl *preferDefinitionImpl<ObjCMethodDecl>(clang::Decl *D) { - if (const auto *X = dyn_cast<ObjCMethodDecl>(D)) { - for (auto *I : X->redecls()) - if (I->hasBody()) - return I; - } - return D; -} - -static Decl *getDefinitionOrCanonicalDecl(Decl *D) { - assert(D); - D = D->getCanonicalDecl(); - D = preferDefinitionImpl<VarDecl>(D); - D = preferDefinitionImpl<FunctionDecl>(D); - D = preferDefinitionImpl<TagDecl>(D); - D = preferDefinitionImpl<ObjCMethodDecl>(D); - assert(D); - return D; -} - //===----------------------------------------------------------------------===// // Path-sensitive checking. //===----------------------------------------------------------------------===// @@ -818,12 +790,13 @@ void AnalysisConsumer::RunPathSensitiveChecks(Decl *D, // FIXME: Inter-procedural analysis will need to handle invalid CFGs. if (!Mgr->getCFG(D)) return; - + auto *DeclContext = Mgr->getAnalysisDeclContext(D); // See if the LiveVariables analysis scales. - if (!Mgr->getAnalysisDeclContext(D)->getAnalysis<RelaxedLiveVariables>()) + if (!DeclContext->getAnalysis<RelaxedLiveVariables>()) return; - const Decl *DefDecl = getDefinitionOrCanonicalDecl(D); + // DeclContext declaration is the redeclaration of D that has a body. + const Decl *DefDecl = DeclContext->getDecl(); // Get the SyntaxRunningTime from the function summary, because it is computed // during the AM_Syntax analysis, which is done at a different point in time _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
