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

Reply via email to