[llvm-branch-commits] [clang] Fix lifetimebound for field access (#100197) (PR #100725)
https://github.com/usx95 created https://github.com/llvm/llvm-project/pull/100725 Fixes: https://github.com/llvm/llvm-project/issues/81589 There is no way to switch this off without `-Wno-dangling`. >From f9e213895548bfaba21399cb337688e8f3839a3a Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Wed, 24 Jul 2024 15:58:52 +0200 Subject: [PATCH] Fix lifetimebound for field access (#100197) Fixes: https://github.com/llvm/llvm-project/issues/81589 There is no way to switch this off without `-Wno-dangling`. --- clang/docs/ReleaseNotes.rst | 3 +++ clang/lib/Sema/CheckExprLifetime.cpp | 9 clang/test/SemaCXX/attr-lifetimebound.cpp | 26 +++ 3 files changed, 38 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 549da6812740f..71d615553c613 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -767,6 +767,9 @@ Improvements to Clang's diagnostics - Clang now diagnoses undefined behavior in constant expressions more consistently. This includes invalid shifts, and signed overflow in arithmetic. +- Clang now diagnoses dangling references to fields of temporary objects. Fixes #GH81589. + + Improvements to Clang's time-trace -- diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp index 5c8ef564f30aa..112cf3d081822 100644 --- a/clang/lib/Sema/CheckExprLifetime.cpp +++ b/clang/lib/Sema/CheckExprLifetime.cpp @@ -7,6 +7,7 @@ //===--===// #include "CheckExprLifetime.h" +#include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/Basic/DiagnosticSema.h" #include "clang/Sema/Initialization.h" @@ -548,6 +549,14 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, EnableLifetimeWarnings); } + if (auto *M = dyn_cast(Init)) { +// Lifetime of a non-reference type field is same as base object. +if (auto *F = dyn_cast(M->getMemberDecl()); +F && !F->getType()->isReferenceType()) + visitLocalsRetainedByInitializer(Path, M->getBase(), Visit, true, + EnableLifetimeWarnings); + } + if (isa(Init)) { if (EnableLifetimeWarnings) handleGslAnnotatedTypes(Path, Init, Visit); diff --git a/clang/test/SemaCXX/attr-lifetimebound.cpp b/clang/test/SemaCXX/attr-lifetimebound.cpp index 70bc545c07bd9..7db0a4d64d259 100644 --- a/clang/test/SemaCXX/attr-lifetimebound.cpp +++ b/clang/test/SemaCXX/attr-lifetimebound.cpp @@ -47,6 +47,31 @@ namespace usage_ok { q = A(); // expected-warning {{object backing the pointer q will be destroyed at the end of the full-expression}} r = A(1); // expected-warning {{object backing the pointer r will be destroyed at the end of the full-expression}} } + + struct FieldCheck { +struct Set { + int a; +}; +struct Pair { + const int& a; + int b; + Set c; + int * d; +}; +Pair p; +FieldCheck(const int& a): p(a){} +Pair& getR() [[clang::lifetimebound]] { return p; } +Pair* getP() [[clang::lifetimebound]] { return &p; } +Pair* getNoLB() { return &p; } + }; + void test_field_access() { +int x = 0; +const int& a = FieldCheck{x}.getR().a; +const int& b = FieldCheck{x}.getP()->b; // expected-warning {{temporary bound to local reference 'b' will be destroyed at the end of the full-expression}} +const int& c = FieldCheck{x}.getP()->c.a; // expected-warning {{temporary bound to local reference 'c' will be destroyed at the end of the full-expression}} +const int& d = FieldCheck{x}.getNoLB()->c.a; +const int* e = FieldCheck{x}.getR().d; + } } # 1 "" 1 3 @@ -239,3 +264,4 @@ namespace move_forward_et_al_examples { S X; S *AddressOfOk = std::addressof(X); } // namespace move_forward_et_al_examples + ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] Fix lifetimebound for field access (#100197) (PR #100725)
https://github.com/usx95 milestoned https://github.com/llvm/llvm-project/pull/100725 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [codegen] Emit missing cleanups for stmt-expr and coro suspensions [take-2] (PR #85398)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/85398 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang-tools-extra] a4f3866 - [clangd] Remove "decision-forest-base" experimental flag.
Author: Utkarsh Saxena Date: 2021-01-13T17:54:38+01:00 New Revision: a4f386688239b06e09f28fd31f93bf761aa9c76f URL: https://github.com/llvm/llvm-project/commit/a4f386688239b06e09f28fd31f93bf761aa9c76f DIFF: https://github.com/llvm/llvm-project/commit/a4f386688239b06e09f28fd31f93bf761aa9c76f.diff LOG: [clangd] Remove "decision-forest-base" experimental flag. The value of this flag can only be fine tuned by using A/B testing on large user base. We do not expect individual users to use and fine tune this flag. Differential Revision: https://reviews.llvm.org/D94513 Added: Modified: clang-tools-extra/clangd/tool/ClangdMain.cpp Removed: diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp index d2c52cf61c53..9c75cafdb08e 100644 --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -194,14 +194,6 @@ opt RankingModel{ Hidden, }; -opt DecisionForestBase{ -"decision-forest-base", -cat(Features), -desc("Base for exponentiating the prediction from DecisionForest."), -init(CodeCompleteOptions().DecisionForestBase), -Hidden, -}; - // FIXME: also support "plain" style where signatures are always omitted. enum CompletionStyleFlag { Detailed, Bundled }; opt CompletionStyle{ @@ -841,7 +833,6 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var Opts.CodeComplete.AllScopes = AllScopesCompletion; Opts.CodeComplete.RunParser = CodeCompletionParse; Opts.CodeComplete.RankingModel = RankingModel; - Opts.CodeComplete.DecisionForestBase = DecisionForestBase; RealThreadsafeFS TFS; std::vector> ProviderStack; ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang-tools-extra] 2f395b7 - [clangd] Make AST-based signals available to runWithPreamble.
Author: Utkarsh Saxena Date: 2021-01-14T18:34:50+01:00 New Revision: 2f395b7092bdac0e39bb4e2bb5e6b03e521a45dd URL: https://github.com/llvm/llvm-project/commit/2f395b7092bdac0e39bb4e2bb5e6b03e521a45dd DIFF: https://github.com/llvm/llvm-project/commit/2f395b7092bdac0e39bb4e2bb5e6b03e521a45dd.diff LOG: [clangd] Make AST-based signals available to runWithPreamble. Many useful signals can be derived from a valid AST which is regularly updated by the ASTWorker. `runWithPreamble` does not have access to the ParsedAST but it can be provided access to some signals derived from a (possibly stale) AST. Differential Revision: https://reviews.llvm.org/D94424 Added: clang-tools-extra/clangd/ASTSignals.cpp clang-tools-extra/clangd/ASTSignals.h clang-tools-extra/clangd/unittests/ASTSignalsTests.cpp Modified: clang-tools-extra/clangd/CMakeLists.txt clang-tools-extra/clangd/TUScheduler.cpp clang-tools-extra/clangd/TUScheduler.h clang-tools-extra/clangd/unittests/CMakeLists.txt clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp Removed: diff --git a/clang-tools-extra/clangd/ASTSignals.cpp b/clang-tools-extra/clangd/ASTSignals.cpp new file mode 100644 index ..da849287bbf6 --- /dev/null +++ b/clang-tools-extra/clangd/ASTSignals.cpp @@ -0,0 +1,42 @@ +//===--- ASTSignals.cpp - LSP server -*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "ASTSignals.h" +#include "AST.h" +#include "FindTarget.h" + +namespace clang { +namespace clangd { +ASTSignals ASTSignals::derive(const ParsedAST &AST) { + ASTSignals Signals; + const SourceManager &SM = AST.getSourceManager(); + findExplicitReferences(AST.getASTContext(), [&](ReferenceLoc Ref) { +for (const NamedDecl *ND : Ref.Targets) { + if (!isInsideMainFile(Ref.NameLoc, SM)) +continue; + SymbolID ID = getSymbolID(ND); + if (!ID) +continue; + unsigned &SymbolCount = Signals.ReferencedSymbols[ID]; + SymbolCount++; + // Process namespace only when we see the symbol for the first time. + if (SymbolCount != 1) +continue; + if (const auto *NSD = dyn_cast(ND->getDeclContext())) { +if (NSD->isAnonymousNamespace()) + continue; +std::string NS = printNamespaceScope(*NSD); +if (!NS.empty()) + Signals.RelatedNamespaces[NS]++; + } +} + }); + return Signals; +} +} // namespace clangd +} // namespace clang diff --git a/clang-tools-extra/clangd/ASTSignals.h b/clang-tools-extra/clangd/ASTSignals.h new file mode 100644 index ..bc70cd17310a --- /dev/null +++ b/clang-tools-extra/clangd/ASTSignals.h @@ -0,0 +1,39 @@ +//===--- ASTSignals.h - LSP server ---*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_ASTSIGNALS_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_ASTSIGNALS_H + +#include "ParsedAST.h" +#include "index/SymbolID.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" + +namespace clang { +namespace clangd { + +/// Signals derived from a valid AST of a file. +/// Provides information that can only be extracted from the AST to actions that +/// can't access an AST. The signals are computed and updated asynchronously by +/// the ASTWorker and thus they are always stale and also can be absent. +/// Example usage: Information about the declarations used in a file affects +/// code-completion ranking in that file. +struct ASTSignals { + /// Number of occurrences of each symbol present in the file. + llvm::DenseMap ReferencedSymbols; + /// Namespaces whose symbols are used in the file, and the number of such + /// distinct symbols. + llvm::StringMap RelatedNamespaces; + + static ASTSignals derive(const ParsedAST &AST); +}; + +} // namespace clangd +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_ASTSIGNALS_H diff --git a/clang-tools-extra/clangd/CMakeLists.txt b/clang-tools-extra/clangd/CMakeLists.txt index 9e62e0948027..1d12e7e2355d 100644 --- a/clang-tools-extra/clangd/CMakeLists.txt +++ b/clang-tools-extra/clangd/CMakeLists.txt @@ -46,6 +46,7 @@ include_directories(BEFORE "${CMAKE_CURRENT_BINARY_DIR}/../clang-tidy") add_clang_library(clangDaemon AST.cpp + ASTSignals.cpp ClangdLSPServer.cpp ClangdServer.cpp CodeComplete.cpp diff --git a/clang-tools-
[llvm-branch-commits] [clang-tools-extra] 8b09cf7 - [clangd] Trivial: Documentation fix in ASTSignals.
Author: Utkarsh Saxena Date: 2021-01-14T18:38:42+01:00 New Revision: 8b09cf7956d8abc722fa736874e4cea667a9d3cb URL: https://github.com/llvm/llvm-project/commit/8b09cf7956d8abc722fa736874e4cea667a9d3cb DIFF: https://github.com/llvm/llvm-project/commit/8b09cf7956d8abc722fa736874e4cea667a9d3cb.diff LOG: [clangd] Trivial: Documentation fix in ASTSignals. Added: Modified: clang-tools-extra/clangd/ASTSignals.cpp clang-tools-extra/clangd/ASTSignals.h Removed: diff --git a/clang-tools-extra/clangd/ASTSignals.cpp b/clang-tools-extra/clangd/ASTSignals.cpp index da849287bbf6..b8cc7f05927a 100644 --- a/clang-tools-extra/clangd/ASTSignals.cpp +++ b/clang-tools-extra/clangd/ASTSignals.cpp @@ -1,4 +1,4 @@ -//===--- ASTSignals.cpp - LSP server -*- C++-*-===// +//===--- ASTSignals.cpp --*- C++-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/clang-tools-extra/clangd/ASTSignals.h b/clang-tools-extra/clangd/ASTSignals.h index bc70cd17310a..fd31be38ce8b 100644 --- a/clang-tools-extra/clangd/ASTSignals.h +++ b/clang-tools-extra/clangd/ASTSignals.h @@ -1,4 +1,4 @@ -//===--- ASTSignals.h - LSP server ---*- C++-*-===// +//===--- ASTSignals.h *- C++-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang-tools-extra] d5047d7 - [clangd] Update CC Ranking model with better sampling.
Author: Utkarsh Saxena Date: 2021-01-15T18:13:24+01:00 New Revision: d5047d762f391c94939d67fc84cae25b24125694 URL: https://github.com/llvm/llvm-project/commit/d5047d762f391c94939d67fc84cae25b24125694 DIFF: https://github.com/llvm/llvm-project/commit/d5047d762f391c94939d67fc84cae25b24125694.diff LOG: [clangd] Update CC Ranking model with better sampling. A better sampling strategy was used to generate the dataset for this model. New signals introduced in this model: - NumNameInContext: Number of words in the context that matches the name of the candidate. - FractionNameInContext: Fraction of the words in context matching the name of the candidate. We remove the signal `IsForbidden` from the model and down rank forbidden signals aggresively. Differential Revision: https://reviews.llvm.org/D94697 Added: Modified: clang-tools-extra/clangd/Quality.cpp clang-tools-extra/clangd/quality/model/features.json clang-tools-extra/clangd/quality/model/forest.json Removed: error: too big or took too long to generate ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang-tools-extra] 0f9908a - [clangd] Use empty() instead of size()>0
Author: Utkarsh Saxena Date: 2021-01-17T15:13:01+01:00 New Revision: 0f9908a7c9c547f2675e00f88cc11ec02ca28e8d URL: https://github.com/llvm/llvm-project/commit/0f9908a7c9c547f2675e00f88cc11ec02ca28e8d DIFF: https://github.com/llvm/llvm-project/commit/0f9908a7c9c547f2675e00f88cc11ec02ca28e8d.diff LOG: [clangd] Use empty() instead of size()>0 Added: Modified: clang-tools-extra/clangd/Quality.cpp Removed: diff --git a/clang-tools-extra/clangd/Quality.cpp b/clang-tools-extra/clangd/Quality.cpp index 7b6a76584778..f076b44f5743 100644 --- a/clang-tools-extra/clangd/Quality.cpp +++ b/clang-tools-extra/clangd/Quality.cpp @@ -512,7 +512,7 @@ evaluateDecisionForest(const SymbolQualitySignals &Quality, E.setIsNameInContext(NumMatch > 0); E.setNumNameInContext(NumMatch); E.setFractionNameInContext( - Relevance.ContextWords && Relevance.ContextWords->size() > 0 + Relevance.ContextWords && Relevance.ContextWords->empty() ? NumMatch * 1.0 / Relevance.ContextWords->size() : 0); E.setIsInBaseClass(Relevance.InBaseClass); ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang-tools-extra] 9abbc05 - [clangd] Use !empty() instead of size()>0
Author: Utkarsh Saxena Date: 2021-01-17T15:26:40+01:00 New Revision: 9abbc050974ff117b79e8e049c52c56db3f49aec URL: https://github.com/llvm/llvm-project/commit/9abbc050974ff117b79e8e049c52c56db3f49aec DIFF: https://github.com/llvm/llvm-project/commit/9abbc050974ff117b79e8e049c52c56db3f49aec.diff LOG: [clangd] Use !empty() instead of size()>0 Added: Modified: clang-tools-extra/clangd/Quality.cpp Removed: diff --git a/clang-tools-extra/clangd/Quality.cpp b/clang-tools-extra/clangd/Quality.cpp index f076b44f5743..27b959ecacb3 100644 --- a/clang-tools-extra/clangd/Quality.cpp +++ b/clang-tools-extra/clangd/Quality.cpp @@ -512,7 +512,7 @@ evaluateDecisionForest(const SymbolQualitySignals &Quality, E.setIsNameInContext(NumMatch > 0); E.setNumNameInContext(NumMatch); E.setFractionNameInContext( - Relevance.ContextWords && Relevance.ContextWords->empty() + Relevance.ContextWords && !Relevance.ContextWords->empty() ? NumMatch * 1.0 / Relevance.ContextWords->size() : 0); E.setIsInBaseClass(Relevance.InBaseClass); ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang-tools-extra] 275716d - [clangd] Derive new signals in CC from ASTSignals.
Author: Utkarsh Saxena Date: 2021-01-18T17:37:27+01:00 New Revision: 275716d6db79a6da3d5cee12139dd0c0abf8fd07 URL: https://github.com/llvm/llvm-project/commit/275716d6db79a6da3d5cee12139dd0c0abf8fd07 DIFF: https://github.com/llvm/llvm-project/commit/275716d6db79a6da3d5cee12139dd0c0abf8fd07.diff LOG: [clangd] Derive new signals in CC from ASTSignals. This patch only introduces new signals but does not use their value in scoring a CC candidate. Usage of these signals in CC ranking in both heiristics and ML model will be introduced in later patches. Differential Revision: https://reviews.llvm.org/D94473 Added: Modified: clang-tools-extra/clangd/ClangdServer.cpp clang-tools-extra/clangd/CodeComplete.cpp clang-tools-extra/clangd/CodeComplete.h clang-tools-extra/clangd/Quality.cpp clang-tools-extra/clangd/Quality.h clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp Removed: diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp index 4f3a47dff05d..a76250fa168e 100644 --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -255,6 +255,7 @@ void ClangdServer::codeComplete(PathRef File, Position Pos, ParseInput.Opts.BuildRecoveryAST = BuildRecoveryAST; ParseInput.Opts.PreserveRecoveryASTType = PreserveRecoveryASTType; +CodeCompleteOpts.MainFileSignals = IP->Signals; // FIXME(ibiryukov): even if Preamble is non-null, we may want to check // both the old and the new version in case only one of them matches. CodeCompleteResult Result = clangd::codeComplete( diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index b3b40022fbb2..9cc18ae789d5 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -1685,6 +1685,7 @@ class CodeCompleteFlow { if (PreferredType) Relevance.HadContextType = true; Relevance.ContextWords = &ContextWords; +Relevance.MainFileSignals = Opts.MainFileSignals; auto &First = Bundle.front(); if (auto FuzzyScore = fuzzyScore(First)) diff --git a/clang-tools-extra/clangd/CodeComplete.h b/clang-tools-extra/clangd/CodeComplete.h index ddcbd487ecc6..debf71d4117c 100644 --- a/clang-tools-extra/clangd/CodeComplete.h +++ b/clang-tools-extra/clangd/CodeComplete.h @@ -15,6 +15,7 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CODECOMPLETE_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CODECOMPLETE_H +#include "ASTSignals.h" #include "Compiler.h" #include "Headers.h" #include "Protocol.h" @@ -89,6 +90,7 @@ struct CodeCompleteOptions { /// clangd. const SymbolIndex *Index = nullptr; + const ASTSignals *MainFileSignals = nullptr; /// Include completions that require small corrections, e.g. change '.' to /// '->' on member access etc. bool IncludeFixIts = false; diff --git a/clang-tools-extra/clangd/Quality.cpp b/clang-tools-extra/clangd/Quality.cpp index 27b959ecacb3..1c41b7c7661f 100644 --- a/clang-tools-extra/clangd/Quality.cpp +++ b/clang-tools-extra/clangd/Quality.cpp @@ -294,6 +294,38 @@ void SymbolRelevanceSignals::merge(const Symbol &IndexResult) { if (!(IndexResult.Flags & Symbol::VisibleOutsideFile)) { Scope = AccessibleScope::FileScope; } + if (MainFileSignals) { +MainFileRefs = +std::max(MainFileRefs, + MainFileSignals->ReferencedSymbols.lookup(IndexResult.ID)); +ScopeRefsInFile = +std::max(ScopeRefsInFile, + MainFileSignals->RelatedNamespaces.lookup(IndexResult.Scope)); + } +} + +void SymbolRelevanceSignals::computeASTSignals( +const CodeCompletionResult &SemaResult) { + if (!MainFileSignals) +return; + if ((SemaResult.Kind != CodeCompletionResult::RK_Declaration) && + (SemaResult.Kind != CodeCompletionResult::RK_Pattern)) +return; + if (const NamedDecl *ND = SemaResult.getDeclaration()) { +auto ID = getSymbolID(ND); +if (!ID) + return; +MainFileRefs = +std::max(MainFileRefs, MainFileSignals->ReferencedSymbols.lookup(ID)); +if (const auto *NSD = dyn_cast(ND->getDeclContext())) { + if (NSD->isAnonymousNamespace()) +return; + std::string Scope = printNamespaceScope(*NSD); + if (!Scope.empty()) +ScopeRefsInFile = std::max( +ScopeRefsInFile, MainFileSignals->RelatedNamespaces.lookup(Scope)); +} + } } void SymbolRelevanceSignals::merge(const CodeCompletionResult &SemaCCResult) { @@ -315,6 +347,7 @@ void SymbolRelevanceSignals::merge(const CodeCompletionResult &SemaCCResult) { InBaseClass |= SemaCCResult.InBaseClass; } + computeASTSignals(SemaCCResult); // Declarations are scoped, others (like macros) are assumed global. if (SemaCCResult.Declaration) Scope = std::min(Scope, computeScope(SemaCCResult.Declaration)); diff
[llvm-branch-commits] [clang-tools-extra] 8bf7116 - [clangd] Index local classes, virtual and overriding methods.
Author: Utkarsh Saxena Date: 2021-01-19T16:18:48+01:00 New Revision: 8bf7116d50bfe8cb881273798ff384ed965c05e9 URL: https://github.com/llvm/llvm-project/commit/8bf7116d50bfe8cb881273798ff384ed965c05e9 DIFF: https://github.com/llvm/llvm-project/commit/8bf7116d50bfe8cb881273798ff384ed965c05e9.diff LOG: [clangd] Index local classes, virtual and overriding methods. Previously we did not record local class declarations. Now with features like findImplementation and typeHierarchy, we have a need to index such local classes to accurately report subclasses and implementations of methods. Performance testing results: - No changes in indexing timing. - No significant change in memory usage. - **1%** increase in #relations. - **0.17%** increase in #refs. - **0.22%** increase #symbols. **New index stats** Time to index: **4:13 min** memory usage **543MB** number of symbols: **521.5K** number of refs: **8679K** number of relations: **49K** **Base Index stats** Time to index: **4:15 min** memory usage **542MB** number of symbols: **520K** number of refs: **8664K** number of relations: **48.5K** Fixes: https://github.com/clangd/clangd/issues/644 Differential Revision: https://reviews.llvm.org/D94785 Added: Modified: clang-tools-extra/clangd/index/FileIndex.cpp clang-tools-extra/clangd/index/IndexAction.cpp clang-tools-extra/clangd/index/Serialization.cpp clang-tools-extra/clangd/index/SymbolCollector.cpp clang-tools-extra/clangd/index/SymbolCollector.h clang-tools-extra/clangd/test/index-serialization/Inputs/sample.idx clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp clang-tools-extra/clangd/unittests/XRefsTests.cpp Removed: diff --git a/clang-tools-extra/clangd/index/FileIndex.cpp b/clang-tools-extra/clangd/index/FileIndex.cpp index 143e76863777..26084c288674 100644 --- a/clang-tools-extra/clangd/index/FileIndex.cpp +++ b/clang-tools-extra/clangd/index/FileIndex.cpp @@ -61,7 +61,8 @@ SlabTuple indexSymbols(ASTContext &AST, std::shared_ptr PP, // We only need declarations, because we don't count references. IndexOpts.SystemSymbolFilter = index::IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly; - IndexOpts.IndexFunctionLocals = false; + // We index function-local classes and its member functions only. + IndexOpts.IndexFunctionLocals = true; if (IsIndexMainAST) { // We only collect refs when indexing main AST. CollectorOpts.RefFilter = RefKind::All; diff --git a/clang-tools-extra/clangd/index/IndexAction.cpp b/clang-tools-extra/clangd/index/IndexAction.cpp index aa65008b51c0..e5a48df90b4d 100644 --- a/clang-tools-extra/clangd/index/IndexAction.cpp +++ b/clang-tools-extra/clangd/index/IndexAction.cpp @@ -212,6 +212,8 @@ std::unique_ptr createStaticIndexingAction( index::IndexingOptions IndexOpts; IndexOpts.SystemSymbolFilter = index::IndexingOptions::SystemSymbolFilterKind::All; + // We index function-local classes and its member functions only. + IndexOpts.IndexFunctionLocals = true; Opts.CollectIncludePath = true; if (Opts.Origin == SymbolOrigin::Unknown) Opts.Origin = SymbolOrigin::Static; diff --git a/clang-tools-extra/clangd/index/Serialization.cpp b/clang-tools-extra/clangd/index/Serialization.cpp index bba5eaa36754..ad1299aa1445 100644 --- a/clang-tools-extra/clangd/index/Serialization.cpp +++ b/clang-tools-extra/clangd/index/Serialization.cpp @@ -452,7 +452,7 @@ readCompileCommand(Reader CmdReader, llvm::ArrayRef Strings) { // The current versioning scheme is simple - non-current versions are rejected. // If you make a breaking change, bump this version number to invalidate stored // data. Later we may want to support some backward compatibility. -constexpr static uint32_t Version = 15; +constexpr static uint32_t Version = 16; llvm::Expected readRIFF(llvm::StringRef Data) { auto RIFF = riff::readFile(Data); diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp index 20f2eacafb27..b1363c1f9cef 100644 --- a/clang-tools-extra/clangd/index/SymbolCollector.cpp +++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp @@ -223,6 +223,11 @@ bool SymbolCollector::shouldCollectSymbol(const NamedDecl &ND, if (!IsMainFileOnly && ND.isInAnonymousNamespace()) return false; + // For function local symbols, index only classes and its member functions. + if (index::isFunctionLocalSymbol(&ND)) +return isa(ND) || + (ND.isCXXInstanceMember() && ND.isFunctionOrFunctionTemplate()); + // We want most things but not "local" symbols such as symbols inside // FunctionDecl, BlockDecl, ObjCMethodDecl and OMPDeclareReductionDecl. // FIXME: Need a matcher for ExportDecl in order to include symbols declared diff --git a/clang-tools-extra/clangd/index/Symbo
[llvm-branch-commits] [clang-tools-extra] 17846ed - [clangd] Use ASTSignals in Heuristics CC Ranking.
Author: Utkarsh Saxena Date: 2021-01-19T19:48:42+01:00 New Revision: 17846ed5af4a83334ef7d07f0b4a9d525e6ec0db URL: https://github.com/llvm/llvm-project/commit/17846ed5af4a83334ef7d07f0b4a9d525e6ec0db DIFF: https://github.com/llvm/llvm-project/commit/17846ed5af4a83334ef7d07f0b4a9d525e6ec0db.diff LOG: [clangd] Use ASTSignals in Heuristics CC Ranking. Differential Revision: https://reviews.llvm.org/D94927 Added: Modified: clang-tools-extra/clangd/Quality.cpp Removed: diff --git a/clang-tools-extra/clangd/Quality.cpp b/clang-tools-extra/clangd/Quality.cpp index 1c41b7c7661f..b49392bc7d04 100644 --- a/clang-tools-extra/clangd/Quality.cpp +++ b/clang-tools-extra/clangd/Quality.cpp @@ -474,6 +474,21 @@ float SymbolRelevanceSignals::evaluateHeuristics() const { if (NeedsFixIts) Score *= 0.5f; + // Use a sigmoid style boosting function similar to `References`, which flats + // out nicely for large values. This avoids a sharp gradient for heavily + // referenced symbols. Use smaller gradient for ScopeRefsInFile since ideally + // MainFileRefs <= ScopeRefsInFile. + if (MainFileRefs >= 2) { +// E.g.: (2, 1.12), (9, 2.0), (48, 3.0). +float S = std::pow(MainFileRefs, -0.11); +Score *= 11.0 * (1 - S) / (1 + S) + 0.7; + } + if (ScopeRefsInFile >= 2) { +// E.g.: (2, 1.04), (14, 2.0), (109, 3.0), (400, 3.6). +float S = std::pow(ScopeRefsInFile, -0.10); +Score *= 10.0 * (1 - S) / (1 + S) + 0.7; + } + return Score; } ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang-tools-extra] 85c1c6a - [clangd] Add Random Forest runtime for code completion.
Author: Utkarsh Saxena Date: 2020-09-18T18:27:42+02:00 New Revision: 85c1c6a4ba4eebbd3f5cefb1512498b9f8a5bb7a URL: https://github.com/llvm/llvm-project/commit/85c1c6a4ba4eebbd3f5cefb1512498b9f8a5bb7a DIFF: https://github.com/llvm/llvm-project/commit/85c1c6a4ba4eebbd3f5cefb1512498b9f8a5bb7a.diff LOG: [clangd] Add Random Forest runtime for code completion. Summary: [WIP] - Proposes a json format for representing Random Forest model. - Proposes a way to test the generated runtime using a test model. TODO: - Add generated source code snippet for easier review. - Fix unused label warning. - Figure out required using declarations for CATEGORICAL columns from Features.json. - Necessary Google3 internal modifications for blaze before landing. - Add documentation for format of the model. - Document more. Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D83814 Added: clang-tools-extra/clangd/quality/CompletionModel.cmake clang-tools-extra/clangd/quality/CompletionModelCodegen.py clang-tools-extra/clangd/quality/README.md clang-tools-extra/clangd/quality/model/features.json clang-tools-extra/clangd/quality/model/forest.json clang-tools-extra/clangd/unittests/DecisionForestTests.cpp clang-tools-extra/clangd/unittests/decision_forest_model/CategoricalFeature.h clang-tools-extra/clangd/unittests/decision_forest_model/features.json clang-tools-extra/clangd/unittests/decision_forest_model/forest.json Modified: clang-tools-extra/clangd/CMakeLists.txt clang-tools-extra/clangd/unittests/CMakeLists.txt clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp Removed: diff --git a/clang-tools-extra/clangd/CMakeLists.txt b/clang-tools-extra/clangd/CMakeLists.txt index 3a1a034ed17b..9d2ab5be222a 100644 --- a/clang-tools-extra/clangd/CMakeLists.txt +++ b/clang-tools-extra/clangd/CMakeLists.txt @@ -28,6 +28,9 @@ set(LLVM_LINK_COMPONENTS FrontendOpenMP Option ) + +include(${CMAKE_CURRENT_SOURCE_DIR}/quality/CompletionModel.cmake) +gen_decision_forest(${CMAKE_CURRENT_SOURCE_DIR}/quality/model CompletionModel clang::clangd::Example) if(MSVC AND NOT CLANG_CL) set_source_files_properties(CompileCommands.cpp PROPERTIES COMPILE_FLAGS -wd4130) # disables C4130: logical operation on address of string constant @@ -77,6 +80,7 @@ add_clang_library(clangDaemon TUScheduler.cpp URI.cpp XRefs.cpp + ${CMAKE_CURRENT_BINARY_DIR}/CompletionModel.cpp index/Background.cpp index/BackgroundIndexLoader.cpp @@ -117,6 +121,11 @@ add_clang_library(clangDaemon omp_gen ) +# Include generated CompletionModel headers. +target_include_directories(clangDaemon PUBLIC + $ +) + clang_target_link_libraries(clangDaemon PRIVATE clangAST diff --git a/clang-tools-extra/clangd/quality/CompletionModel.cmake b/clang-tools-extra/clangd/quality/CompletionModel.cmake new file mode 100644 index ..60c6d2aa8433 --- /dev/null +++ b/clang-tools-extra/clangd/quality/CompletionModel.cmake @@ -0,0 +1,37 @@ +# Run the Completion Model Codegenerator on the model present in the +# ${model} directory. +# Produces a pair of files called ${filename}.h and ${filename}.cpp in the +# ${CMAKE_CURRENT_BINARY_DIR}. The generated header +# will define a C++ class called ${cpp_class} - which may be a +# namespace-qualified class name. +function(gen_decision_forest model filename cpp_class) + set(model_compiler ${CMAKE_SOURCE_DIR}/../clang-tools-extra/clangd/quality/CompletionModelCodegen.py) + + set(output_dir ${CMAKE_CURRENT_BINARY_DIR}) + set(header_file ${output_dir}/${filename}.h) + set(cpp_file ${output_dir}/${filename}.cpp) + + add_custom_command(OUTPUT ${header_file} ${cpp_file} +COMMAND "${Python3_EXECUTABLE}" ${model_compiler} + --model ${model} + --output_dir ${output_dir} + --filename ${filename} + --cpp_class ${cpp_class} +COMMENT "Generating code completion model runtime..." +DEPENDS ${model_compiler} ${model}/forest.json ${model}/features.json +VERBATIM ) + + set_source_files_properties(${header_file} PROPERTIES +GENERATED 1) + set_source_files_properties(${cpp_file} PROPERTIES +GENERATED 1) + + # Disable unused label warning for generated files. + if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") +set_source_files_properties(${cpp_file} PROPERTIES + COMPILE_FLAGS /wd4102) + else() +set_source_files_properties(${cpp_file} PROPERTIES + COMPILE_FLAGS -Wno-unused) + endif() +endfunction() diff --git a/clang-tools-extra/clangd/quality/CompletionModelCodegen.py b/clang-tools-extra/clangd/quality/CompletionModelCodegen.py new file mode 100644 index ..8f8234f6ebbc --- /dev/null +++ b/clang-tools-extra/clangd/quality/CompletionModelCodegen.py @@ -0,0 +1,283 @@ +"""Code generator for Code Comp
[llvm-branch-commits] [clang-tools-extra] b31486a - [clangd] textDocument/implementation (LSP layer)
Author: Utkarsh Saxena Date: 2020-11-23T13:50:44+01:00 New Revision: b31486ad971774c859e3e031fc0d8d9b77e3b083 URL: https://github.com/llvm/llvm-project/commit/b31486ad971774c859e3e031fc0d8d9b77e3b083 DIFF: https://github.com/llvm/llvm-project/commit/b31486ad971774c859e3e031fc0d8d9b77e3b083.diff LOG: [clangd] textDocument/implementation (LSP layer) Differential Revision: https://reviews.llvm.org/D91721 Added: clang-tools-extra/clangd/test/implementations.test Modified: clang-tools-extra/clangd/ClangdLSPServer.cpp clang-tools-extra/clangd/ClangdLSPServer.h clang-tools-extra/clangd/ClangdServer.cpp clang-tools-extra/clangd/ClangdServer.h clang-tools-extra/clangd/test/initialize-params.test Removed: diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp index e726271fe7cbe..335a6fc9ad94e 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -604,6 +604,7 @@ void ClangdLSPServer::onInitialize(const InitializeParams &Params, }}, {"declarationProvider", true}, {"definitionProvider", true}, +{"implementationProvider", true}, {"documentHighlightProvider", true}, {"documentLinkProvider", llvm::json::Object{ @@ -1291,6 +1292,22 @@ void ClangdLSPServer::onReference(const ReferenceParams &Params, }); } +void ClangdLSPServer::onGoToImplementation( +const TextDocumentPositionParams &Params, +Callback> Reply) { + Server->findImplementations( + Params.textDocument.uri.file(), Params.position, + [Reply = std::move(Reply)]( + llvm::Expected> Overrides) mutable { +if (!Overrides) + return Reply(Overrides.takeError()); +std::vector Impls; +for (const LocatedSymbol &Sym : *Overrides) + Impls.push_back(Sym.PreferredDeclaration); +return Reply(std::move(Impls)); + }); +} + void ClangdLSPServer::onSymbolInfo(const TextDocumentPositionParams &Params, Callback> Reply) { Server->symbolInfo(Params.textDocument.uri.file(), Params.position, @@ -1431,6 +1448,7 @@ ClangdLSPServer::ClangdLSPServer(class Transport &Transp, MsgHandler->bind("textDocument/signatureHelp", &ClangdLSPServer::onSignatureHelp); MsgHandler->bind("textDocument/definition", &ClangdLSPServer::onGoToDefinition); MsgHandler->bind("textDocument/declaration", &ClangdLSPServer::onGoToDeclaration); + MsgHandler->bind("textDocument/implementation", &ClangdLSPServer::onGoToImplementation); MsgHandler->bind("textDocument/references", &ClangdLSPServer::onReference); MsgHandler->bind("textDocument/switchSourceHeader", &ClangdLSPServer::onSwitchSourceHeader); MsgHandler->bind("textDocument/prepareRename", &ClangdLSPServer::onPrepareRename); diff --git a/clang-tools-extra/clangd/ClangdLSPServer.h b/clang-tools-extra/clangd/ClangdLSPServer.h index b9200f6a2e1b8..4d568bc13d8bf 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.h +++ b/clang-tools-extra/clangd/ClangdLSPServer.h @@ -115,6 +115,8 @@ class ClangdLSPServer : private ClangdServer::Callbacks { Callback>); void onGoToDefinition(const TextDocumentPositionParams &, Callback>); + void onGoToImplementation(const TextDocumentPositionParams &, +Callback>); void onReference(const ReferenceParams &, Callback>); void onSwitchSourceHeader(const TextDocumentIdentifier &, Callback>); diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp index b6f9fcfd23da8..889d2cbcf2807 100644 --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -718,6 +718,18 @@ void ClangdServer::foldingRanges(llvm::StringRef File, TUScheduler::InvalidateOnUpdate); } +void ClangdServer::findImplementations( +PathRef File, Position Pos, Callback> CB) { + auto Action = [Pos, CB = std::move(CB), + this](llvm::Expected InpAST) mutable { +if (!InpAST) + return CB(InpAST.takeError()); +CB(clangd::findImplementations(InpAST->AST, Pos, Index)); + }; + + WorkScheduler.runWithAST("Implementations", File, std::move(Action)); +} + void ClangdServer::findReferences(PathRef File, Position Pos, uint32_t Limit, Callback CB) { auto Action = [Pos, Limit, CB = std::move(CB), diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h index 0056f5072cca3..1ccb4c5899f81 100644 --- a/clang-tools-extra/clangd/ClangdServer.h +++ b/clang-tools-extra/clangd/ClangdServer.h @@ -253,6 +253,10 @@ class ClangdServer { /// Retrieve ranges that
[llvm-branch-commits] [clang-tools-extra] 4ce242a - [clangd] Find relations in Dex exploration tool.
Author: Utkarsh Saxena Date: 2020-12-10T16:54:03+01:00 New Revision: 4ce242a163c3b98385a5cb949a7e6b1e1ae7eb83 URL: https://github.com/llvm/llvm-project/commit/4ce242a163c3b98385a5cb949a7e6b1e1ae7eb83 DIFF: https://github.com/llvm/llvm-project/commit/4ce242a163c3b98385a5cb949a7e6b1e1ae7eb83.diff LOG: [clangd] Find relations in Dex exploration tool. Reviewed By: hokein Differential Revision: https://reviews.llvm.org/D93029 Added: Modified: clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp Removed: diff --git a/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp b/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp index d7da330e2ed0..49f16e72be92 100644 --- a/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp +++ b/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp @@ -11,6 +11,8 @@ // //===--===// +#include "index/Index.h" +#include "index/Relation.h" #include "index/Serialization.h" #include "index/dex/Dex.h" #include "index/remote/Client.h" @@ -267,6 +269,43 @@ class Refs : public Command { } }; +class Relations : public Command { + llvm::cl::opt ID{ + "id", + llvm::cl::Positional, + llvm::cl::desc("Symbol ID of the symbol being queried (hex)."), + }; + llvm::cl::opt Relation{ + "relation", + llvm::cl::desc("Relation kind for the predicate."), + values(clEnumValN(RelationKind::BaseOf, "base_of", +"Find subclasses of a class."), + clEnumValN(RelationKind::OverriddenBy, "overridden_by", +"Find methods that overrides a virtual method.")), + }; + + void run() override { +if (ID.getNumOccurrences() == 0 || Relation.getNumOccurrences() == 0) { + llvm::errs() + << "Missing required argument: please provide id and -relation.\n"; + return; +} +RelationsRequest Req; +if (ID.getNumOccurrences()) { + auto SID = SymbolID::fromStr(ID); + if (!SID) { +llvm::errs() << llvm::toString(SID.takeError()) << "\n"; +return; + } + Req.Subjects.insert(*SID); +} +Req.Predicate = Relation.getValue(); +Index->relations(Req, [](const SymbolID &SID, const Symbol &S) { + llvm::outs() << toYAML(S); +}); + } +}; + class Export : public Command { llvm::cl::opt Format{ "format", @@ -326,6 +365,8 @@ struct { {"lookup", "Dump symbol details by ID or qualified name", std::make_unique}, {"refs", "Find references by ID or qualified name", std::make_unique}, +{"relations", "Find relations by ID and relation kind", + std::make_unique}, {"export", "Export index", std::make_unique}, }; ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [Serialization] Code cleanups and polish 83233 (PR #83237)
usx95 wrote: > I tried to take a look at eigen and it looks like the declaration looks well > and I had no clue how that happens. A reproducer may be necessary here to > proceed. Thanks in advance. I can reproduce using the following sources and invocations outlined in `run.sh` https://github.com/usx95/llvm-project/commit/363d877bd317638b197f57c3591860e1688950d5 ```sh > module-reproducer/run.sh Building sensor_data.cc Building tensor.cc Building base.cc In module 'sensor_data': ../../eigen/Eigen/src/Core/../plugins/CommonCwiseBinaryOps.inc:47:29: warning: inline function 'Eigen::operator*' is not defined [-Wundefined-inline] 47 | EIGEN_MAKE_SCALAR_BINARY_OP(operator*, product) | ^ ../../eigen/Eigen/src/Geometry/AngleAxis.h:221:35: note: used here 221 | Vector3 sin_axis = sin(m_angle) * m_axis; | ^ 1 warning generated. ``` This warning is a new breakage and does not happed without this change (ignore the linker failure). https://github.com/llvm/llvm-project/pull/83237 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] release/20.x: [clang] Fix false positive regression for lifetime analysis warning. (#127460) (PR #127618)
https://github.com/usx95 approved this pull request. https://github.com/llvm/llvm-project/pull/127618 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Propagate loans using dataflow analysis (PR #147295)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/147295 >From dd2dd838f44ebeb6d45f75af2934159ee61b385b Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Sun, 6 Jul 2025 19:12:55 + Subject: [PATCH] [LifetimeSafety] Propagate loans using dataflow analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 255 +- .../Sema/warn-lifetime-safety-dataflow.cpp| 186 + 2 files changed, 440 insertions(+), 1 deletion(-) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index 2c2309de90e26..cdbab31ac7a9c 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -482,7 +482,247 @@ class FactGenerator : public ConstStmtVisitor { }; // = // -// TODO: Run dataflow analysis to propagate loans, analyse and error reporting. +// The Dataflow Lattice +// = // + +// Using LLVM's immutable collections is efficient for dataflow analysis +// as it avoids deep copies during state transitions. +// TODO(opt): Consider using a bitset to represent the set of loans. +using LoanSet = llvm::ImmutableSet; +using OriginLoanMap = llvm::ImmutableMap; + +/// An object to hold the factories for immutable collections, ensuring +/// that all created states share the same underlying memory management. +struct LifetimeFactory { + OriginLoanMap::Factory OriginMapFact; + LoanSet::Factory LoanSetFact; + + LoanSet createLoanSet(LoanID LID) { +return LoanSetFact.add(LoanSetFact.getEmptySet(), LID); + } +}; + +/// LifetimeLattice represents the state of our analysis at a given program +/// point. It is an immutable object, and all operations produce a new +/// instance rather than modifying the existing one. +struct LifetimeLattice { + /// The map from an origin to the set of loans it contains. + /// TODO(opt): To reduce the lattice size, propagate origins of declarations, + /// not expressions, because expressions are not visible across blocks. + OriginLoanMap Origins = OriginLoanMap(nullptr); + + explicit LifetimeLattice(const OriginLoanMap &S) : Origins(S) {} + LifetimeLattice() = default; + + bool operator==(const LifetimeLattice &Other) const { +return Origins == Other.Origins; + } + bool operator!=(const LifetimeLattice &Other) const { +return !(*this == Other); + } + + LoanSet getLoans(OriginID OID, LifetimeFactory &Factory) const { +if (auto *Loans = Origins.lookup(OID)) + return *Loans; +return Factory.LoanSetFact.getEmptySet(); + } + + /// Computes the union of two lattices by performing a key-wise join of + /// their OriginLoanMaps. + // TODO(opt): This key-wise join is a performance bottleneck. A more + // efficient merge could be implemented using a Patricia Trie or HAMT + // instead of the current AVL-tree-based ImmutableMap. + LifetimeLattice join(const LifetimeLattice &Other, + LifetimeFactory &Factory) const { +/// Merge the smaller map into the larger one ensuring we iterate over the +/// smaller map. +if (Origins.getHeight() < Other.Origins.getHeight()) + return Other.join(*this, Factory); + +OriginLoanMap JoinedState = Origins; +// For each origin in the other map, union its loan set with ours. +for (const auto &Entry : Other.Origins) { + OriginID OID = Entry.first; + LoanSet OtherLoanSet = Entry.second; + JoinedState = Factory.OriginMapFact.add( + JoinedState, OID, + join(getLoans(OID, Factory), OtherLoanSet, Factory)); +} +return LifetimeLattice(JoinedState); + } + + LoanSet join(LoanSet a, LoanSet b, LifetimeFactory &Factory) const { +/// Merge the smaller set into the larger one ensuring we iterate over the +/// smaller set. +if (a.getHeight() < b.getHeight()) + std::swap(a, b); +LoanSet Result = a; +for (LoanID LID : b) { + /// TODO(opt): Profiling shows that this loop is a major performance + /// bottleneck. Investigate using a BitVector to represent the set of + /// loans for improved join performance. + Result = Factory.LoanSetFact.add(Result, LID); +} +return Result; + } + + void dump(llvm::raw_ostream &OS) const { +OS << "LifetimeLattice State:\n"; +if (Origins.isEmpty()) + OS << " \n"; +for (const auto &Entry : Origins) { + if (Entry.second.isEmpty()) +OS << " Origin " << Entry.first << " contains no loans\n"; + for (const LoanID &LID : Entry.second) +OS << " Origin " << Entry.first << " contains Loan " << LID << "\n"; +} + } +}; + +// = // +// The Transfer Function +// = // +class T
[llvm-branch-commits] [clang] [LifetimeSafety] Implement dataflow analysis for loan propagation (PR #147295)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/147295 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Propagate loans using dataflow analysis (PR #147295)
https://github.com/usx95 created https://github.com/llvm/llvm-project/pull/147295 None >From 2e4261b02b6230a8c79f01a673cc3030cfff3ea7 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Sun, 6 Jul 2025 19:12:55 + Subject: [PATCH 1/6] [LifetimeSafety] Propagate loans using dataflow analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 255 +- .../Sema/warn-lifetime-safety-dataflow.cpp| 186 + 2 files changed, 440 insertions(+), 1 deletion(-) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index 3fe30e36ebd0f..7870352f0287a 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -491,7 +491,247 @@ class FactGenerator : public ConstStmtVisitor { }; // = // -// TODO: Run dataflow analysis to propagate loans, analyse and error reporting. +// The Dataflow Lattice +// = // + +// Using LLVM's immutable collections is efficient for dataflow analysis +// as it avoids deep copies during state transitions. +// TODO(opt): Consider using a bitset to represent the set of loans. +using LoanSet = llvm::ImmutableSet; +using OriginLoanMap = llvm::ImmutableMap; + +/// An object to hold the factories for immutable collections, ensuring +/// that all created states share the same underlying memory management. +struct LifetimeFactory { + OriginLoanMap::Factory OriginMapFact; + LoanSet::Factory LoanSetFact; + + LoanSet createLoanSet(LoanID LID) { +return LoanSetFact.add(LoanSetFact.getEmptySet(), LID); + } +}; + +/// LifetimeLattice represents the state of our analysis at a given program +/// point. It is an immutable object, and all operations produce a new +/// instance rather than modifying the existing one. +struct LifetimeLattice { + /// The map from an origin to the set of loans it contains. + /// TODO(opt): To reduce the lattice size, propagate origins of declarations, + /// not expressions, because expressions are not visible across blocks. + OriginLoanMap Origins = OriginLoanMap(nullptr); + + explicit LifetimeLattice(const OriginLoanMap &S) : Origins(S) {} + LifetimeLattice() = default; + + bool operator==(const LifetimeLattice &Other) const { +return Origins == Other.Origins; + } + bool operator!=(const LifetimeLattice &Other) const { +return !(*this == Other); + } + + LoanSet getLoans(OriginID OID, LifetimeFactory &Factory) const { +if (auto *Loans = Origins.lookup(OID)) + return *Loans; +return Factory.LoanSetFact.getEmptySet(); + } + + /// Computes the union of two lattices by performing a key-wise join of + /// their OriginLoanMaps. + // TODO(opt): This key-wise join is a performance bottleneck. A more + // efficient merge could be implemented using a Patricia Trie or HAMT + // instead of the current AVL-tree-based ImmutableMap. + LifetimeLattice join(const LifetimeLattice &Other, + LifetimeFactory &Factory) const { +/// Merge the smaller map into the larger one ensuring we iterate over the +/// smaller map. +if (Origins.getHeight() < Other.Origins.getHeight()) + return Other.join(*this, Factory); + +OriginLoanMap JoinedState = Origins; +// For each origin in the other map, union its loan set with ours. +for (const auto &Entry : Other.Origins) { + OriginID OID = Entry.first; + LoanSet OtherLoanSet = Entry.second; + JoinedState = Factory.OriginMapFact.add( + JoinedState, OID, + join(getLoans(OID, Factory), OtherLoanSet, Factory)); +} +return LifetimeLattice(JoinedState); + } + + LoanSet join(LoanSet a, LoanSet b, LifetimeFactory &Factory) const { +/// Merge the smaller set into the larger one ensuring we iterate over the +/// smaller set. +if (a.getHeight() < b.getHeight()) + std::swap(a, b); +LoanSet Result = a; +for (LoanID LID : b) { + /// TODO(opt): Profiling shows that this loop is a major performance + /// bottleneck. Investigate using a BitVector to represent the set of + /// loans for improved join performance. + Result = Factory.LoanSetFact.add(Result, LID); +} +return Result; + } + + void dump(llvm::raw_ostream &OS) const { +OS << "LifetimeLattice State:\n"; +if (Origins.isEmpty()) + OS << " \n"; +for (const auto &Entry : Origins) { + if (Entry.second.isEmpty()) +OS << " Origin " << Entry.first << " contains no loans\n"; + for (const LoanID &LID : Entry.second) +OS << " Origin " << Entry.first << " contains Loan " << LID << "\n"; +} + } +}; + +// = // +// The Transfer Function +// = /
[llvm-branch-commits] [clang] [LifetimeSafety] Propagate loans using dataflow analysis (PR #147295)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/147295 >From 2e4261b02b6230a8c79f01a673cc3030cfff3ea7 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Sun, 6 Jul 2025 19:12:55 + Subject: [PATCH 1/6] [LifetimeSafety] Propagate loans using dataflow analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 255 +- .../Sema/warn-lifetime-safety-dataflow.cpp| 186 + 2 files changed, 440 insertions(+), 1 deletion(-) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index 3fe30e36ebd0f..7870352f0287a 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -491,7 +491,247 @@ class FactGenerator : public ConstStmtVisitor { }; // = // -// TODO: Run dataflow analysis to propagate loans, analyse and error reporting. +// The Dataflow Lattice +// = // + +// Using LLVM's immutable collections is efficient for dataflow analysis +// as it avoids deep copies during state transitions. +// TODO(opt): Consider using a bitset to represent the set of loans. +using LoanSet = llvm::ImmutableSet; +using OriginLoanMap = llvm::ImmutableMap; + +/// An object to hold the factories for immutable collections, ensuring +/// that all created states share the same underlying memory management. +struct LifetimeFactory { + OriginLoanMap::Factory OriginMapFact; + LoanSet::Factory LoanSetFact; + + LoanSet createLoanSet(LoanID LID) { +return LoanSetFact.add(LoanSetFact.getEmptySet(), LID); + } +}; + +/// LifetimeLattice represents the state of our analysis at a given program +/// point. It is an immutable object, and all operations produce a new +/// instance rather than modifying the existing one. +struct LifetimeLattice { + /// The map from an origin to the set of loans it contains. + /// TODO(opt): To reduce the lattice size, propagate origins of declarations, + /// not expressions, because expressions are not visible across blocks. + OriginLoanMap Origins = OriginLoanMap(nullptr); + + explicit LifetimeLattice(const OriginLoanMap &S) : Origins(S) {} + LifetimeLattice() = default; + + bool operator==(const LifetimeLattice &Other) const { +return Origins == Other.Origins; + } + bool operator!=(const LifetimeLattice &Other) const { +return !(*this == Other); + } + + LoanSet getLoans(OriginID OID, LifetimeFactory &Factory) const { +if (auto *Loans = Origins.lookup(OID)) + return *Loans; +return Factory.LoanSetFact.getEmptySet(); + } + + /// Computes the union of two lattices by performing a key-wise join of + /// their OriginLoanMaps. + // TODO(opt): This key-wise join is a performance bottleneck. A more + // efficient merge could be implemented using a Patricia Trie or HAMT + // instead of the current AVL-tree-based ImmutableMap. + LifetimeLattice join(const LifetimeLattice &Other, + LifetimeFactory &Factory) const { +/// Merge the smaller map into the larger one ensuring we iterate over the +/// smaller map. +if (Origins.getHeight() < Other.Origins.getHeight()) + return Other.join(*this, Factory); + +OriginLoanMap JoinedState = Origins; +// For each origin in the other map, union its loan set with ours. +for (const auto &Entry : Other.Origins) { + OriginID OID = Entry.first; + LoanSet OtherLoanSet = Entry.second; + JoinedState = Factory.OriginMapFact.add( + JoinedState, OID, + join(getLoans(OID, Factory), OtherLoanSet, Factory)); +} +return LifetimeLattice(JoinedState); + } + + LoanSet join(LoanSet a, LoanSet b, LifetimeFactory &Factory) const { +/// Merge the smaller set into the larger one ensuring we iterate over the +/// smaller set. +if (a.getHeight() < b.getHeight()) + std::swap(a, b); +LoanSet Result = a; +for (LoanID LID : b) { + /// TODO(opt): Profiling shows that this loop is a major performance + /// bottleneck. Investigate using a BitVector to represent the set of + /// loans for improved join performance. + Result = Factory.LoanSetFact.add(Result, LID); +} +return Result; + } + + void dump(llvm::raw_ostream &OS) const { +OS << "LifetimeLattice State:\n"; +if (Origins.isEmpty()) + OS << " \n"; +for (const auto &Entry : Origins) { + if (Entry.second.isEmpty()) +OS << " Origin " << Entry.first << " contains no loans\n"; + for (const LoanID &LID : Entry.second) +OS << " Origin " << Entry.first << " contains Loan " << LID << "\n"; +} + } +}; + +// = // +// The Transfer Function +// = // +cla
[llvm-branch-commits] [clang] [LifetimeSafety] Implement dataflow analysis for loan propagation (PR #147295)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/147295 >From e870b040c4ef29b7ca2e50c1fc0ab5a2446f5cf6 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Sun, 6 Jul 2025 19:12:55 + Subject: [PATCH] [LifetimeSafety] Propagate loans using dataflow analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 258 +- .../Sema/warn-lifetime-safety-dataflow.cpp| 186 + 2 files changed, 443 insertions(+), 1 deletion(-) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index 2c2309de90e26..e881e592ef59f 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -13,7 +13,10 @@ #include "clang/Analysis/Analyses/PostOrderCFGView.h" #include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" +#include "clang/Analysis/FlowSensitive/DataflowWorklist.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/ImmutableSet.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Debug.h" @@ -482,7 +485,247 @@ class FactGenerator : public ConstStmtVisitor { }; // = // -// TODO: Run dataflow analysis to propagate loans, analyse and error reporting. +// The Dataflow Lattice +// = // + +// Using LLVM's immutable collections is efficient for dataflow analysis +// as it avoids deep copies during state transitions. +// TODO(opt): Consider using a bitset to represent the set of loans. +using LoanSet = llvm::ImmutableSet; +using OriginLoanMap = llvm::ImmutableMap; + +/// An object to hold the factories for immutable collections, ensuring +/// that all created states share the same underlying memory management. +struct LifetimeFactory { + OriginLoanMap::Factory OriginMapFact; + LoanSet::Factory LoanSetFact; + + LoanSet createLoanSet(LoanID LID) { +return LoanSetFact.add(LoanSetFact.getEmptySet(), LID); + } +}; + +/// LifetimeLattice represents the state of our analysis at a given program +/// point. It is an immutable object, and all operations produce a new +/// instance rather than modifying the existing one. +struct LifetimeLattice { + /// The map from an origin to the set of loans it contains. + /// TODO(opt): To reduce the lattice size, propagate origins of declarations, + /// not expressions, because expressions are not visible across blocks. + OriginLoanMap Origins = OriginLoanMap(nullptr); + + explicit LifetimeLattice(const OriginLoanMap &S) : Origins(S) {} + LifetimeLattice() = default; + + bool operator==(const LifetimeLattice &Other) const { +return Origins == Other.Origins; + } + bool operator!=(const LifetimeLattice &Other) const { +return !(*this == Other); + } + + LoanSet getLoans(OriginID OID, LifetimeFactory &Factory) const { +if (auto *Loans = Origins.lookup(OID)) + return *Loans; +return Factory.LoanSetFact.getEmptySet(); + } + + /// Computes the union of two lattices by performing a key-wise join of + /// their OriginLoanMaps. + // TODO(opt): This key-wise join is a performance bottleneck. A more + // efficient merge could be implemented using a Patricia Trie or HAMT + // instead of the current AVL-tree-based ImmutableMap. + LifetimeLattice join(const LifetimeLattice &Other, + LifetimeFactory &Factory) const { +/// Merge the smaller map into the larger one ensuring we iterate over the +/// smaller map. +if (Origins.getHeight() < Other.Origins.getHeight()) + return Other.join(*this, Factory); + +OriginLoanMap JoinedState = Origins; +// For each origin in the other map, union its loan set with ours. +for (const auto &Entry : Other.Origins) { + OriginID OID = Entry.first; + LoanSet OtherLoanSet = Entry.second; + JoinedState = Factory.OriginMapFact.add( + JoinedState, OID, + join(getLoans(OID, Factory), OtherLoanSet, Factory)); +} +return LifetimeLattice(JoinedState); + } + + LoanSet join(LoanSet a, LoanSet b, LifetimeFactory &Factory) const { +/// Merge the smaller set into the larger one ensuring we iterate over the +/// smaller set. +if (a.getHeight() < b.getHeight()) + std::swap(a, b); +LoanSet Result = a; +for (LoanID LID : b) { + /// TODO(opt): Profiling shows that this loop is a major performance + /// bottleneck. Investigate using a BitVector to represent the set of + /// loans for improved join performance. + Result = Factory.LoanSetFact.add(Result, LID); +} +return Result; + } + + void dump(llvm::raw_ostream &OS) const { +OS << "LifetimeLattice State:\n"; +if (Origins.isEmpty()) + OS << " \n"; +for (const auto &Entry : Origins) { + if (Entry.second.isEmpty()) +OS
[llvm-branch-commits] [clang] [LifetimeSafety] Implement dataflow analysis for loan propagation (PR #147295)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/147295 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Implement dataflow analysis for loan propagation (PR #147295)
https://github.com/usx95 ready_for_review https://github.com/llvm/llvm-project/pull/147295 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add script performance benchmarking (PR #147315)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/147315 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] Users/usx95/lifetime safety benchmarking (PR #147315)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/147315 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add script performance benchmarking (PR #147315)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/147315 >From 0fbfd74d23b6cd26ef0480f7b9061b2f4a745338 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 7 Jul 2025 15:13:00 + Subject: [PATCH 1/2] [LifetimeSafety] Add script performance benchmarking --- clang/lib/Analysis/LifetimeSafety.cpp | 7 +- .../Analysis/lifetime_safety/benchmark.py | 215 ++ 2 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 clang/test/Analysis/lifetime_safety/benchmark.py diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index e881e592ef59f..1c83b5051bad1 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -151,7 +151,12 @@ class OriginManager { OriginID get(const ValueDecl &D) { auto It = DeclToOriginID.find(&D); -assert(It != DeclToOriginID.end()); +// TODO: This should be an assert(It != ExprToOriginID.end()). The current +// implementation falls back to getOrCreate to avoid crashing on +// yet-unhandled pointer expressions, creating an empty origin for them. +if (It == DeclToOriginID.end()) + return getOrCreate(D); + return It->second; } diff --git a/clang/test/Analysis/lifetime_safety/benchmark.py b/clang/test/Analysis/lifetime_safety/benchmark.py new file mode 100644 index 0..ddf32e192de17 --- /dev/null +++ b/clang/test/Analysis/lifetime_safety/benchmark.py @@ -0,0 +1,215 @@ +import sys +import argparse +import subprocess +import tempfile +import json +import os +from datetime import datetime +import numpy as np +from scipy.optimize import curve_fit +from scipy.stats import t + +def generate_cpp_cycle_test(n: int) -> str: +""" +Generates a C++ code snippet with a specified number of pointers in a cycle. +""" +if n <= 0: +return "// Number of variables must be positive." + +cpp_code = "struct MyObj { int id; ~MyObj() {} };\n\n" +cpp_code += f"void long_cycle_{n}(bool condition) {{\n" +for i in range(1, n + 1): +cpp_code += f" MyObj v{i}{{1}};\n" +cpp_code += "\n" +for i in range(1, n + 1): +cpp_code += f" MyObj* p{i} = &v{i};\n" + +cpp_code += "\n while (condition) {\n" +if n > 0: +cpp_code += f"MyObj* temp = p1;\n" +for i in range(1, n): +cpp_code += f"p{i} = p{i+1};\n" +cpp_code += f"p{n} = temp;\n" +cpp_code += " }\n}\n" +cpp_code += f"\nint main() {{ long_cycle_{n}(false); return 0; }}\n" +return cpp_code + +def generate_cpp_merge_test(n: int) -> str: +""" +Generates a C++ code snippet with N independent conditional assignments. +""" +if n <= 0: +return "// Number of variables must be positive." + +cpp_code = "struct MyObj { int id; ~MyObj() {} };\n\n" +cpp_code += f"void conditional_merges_{n}(bool condition) {{\n" +decls = [f"v{i}" for i in range(1, n + 1)] +cpp_code += f" MyObj {', '.join(decls)};\n" +ptr_decls = [f"*p{i} = nullptr" for i in range(1, n + 1)] +cpp_code += f" MyObj {', '.join(ptr_decls)};\n\n" + +for i in range(1, n + 1): +cpp_code += f" if(condition) {{ p{i} = &v{i}; }}\n" + +cpp_code += "}\n" +cpp_code += f"\nint main() {{ conditional_merges_{n}(false); return 0; }}\n" +return cpp_code + +def analyze_trace_file(trace_path: str) -> tuple[float, float]: +""" +Parses the -ftime-trace JSON output to find durations. + +Returns: +A tuple of (lifetime_analysis_duration_us, total_clang_duration_us). +""" +lifetime_duration = 0.0 +total_duration = 0.0 +try: +with open(trace_path, 'r') as f: +trace_data = json.load(f) +for event in trace_data.get('traceEvents', []): +if event.get('name') == 'LifetimeAnalysis': +lifetime_duration += float(event.get('dur', 0)) +if event.get('name') == 'ExecuteCompiler': +total_duration += float(event.get('dur', 0)) + +except (IOError, json.JSONDecodeError) as e: +print(f"Error reading or parsing trace file {trace_path}: {e}", file=sys.stderr) +return 0.0, 0.0 +return lifetime_duration, total_duration + +def power_law(n, c, k): +"""Represents the power law function: y = c * n^k""" +return c * np.power(n, k) + +def human_readable_time(ms: float) -> str: +"""Converts milliseconds to a human-readable string (ms or s).""" +if ms >= 1000: +return f"{ms / 1000:.2f} s" +return f"{ms:.2f} ms" + +def generate_markdown_report(results: dict) -> str: +"""Generates a Markdown-formatted report from the benchmark results.""" +report = [] +timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S %Z") +report.append(f"# Lifetime Analysis Performance Report") +report.append(f"> Generated on: {timestamp}") +report.append("\n---\n") + +for test_typ
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/147315 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/147315 >From 014d81d9da31df3cf46bd8fc5f7cb470b3271b8e Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 7 Jul 2025 15:13:00 + Subject: [PATCH] [LifetimeSafety] Add script performance benchmarking --- clang/lib/Analysis/LifetimeSafety.cpp | 7 +- .../Analysis/LifetimeSafety/CMakeLists.txt| 49 +++ .../test/Analysis/LifetimeSafety/benchmark.py | 308 ++ .../Analysis/LifetimeSafety/requirements.txt | 2 + clang/test/CMakeLists.txt | 2 + 5 files changed, 367 insertions(+), 1 deletion(-) create mode 100644 clang/test/Analysis/LifetimeSafety/CMakeLists.txt create mode 100644 clang/test/Analysis/LifetimeSafety/benchmark.py create mode 100644 clang/test/Analysis/LifetimeSafety/requirements.txt diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index e881e592ef59f..1c83b5051bad1 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -151,7 +151,12 @@ class OriginManager { OriginID get(const ValueDecl &D) { auto It = DeclToOriginID.find(&D); -assert(It != DeclToOriginID.end()); +// TODO: This should be an assert(It != ExprToOriginID.end()). The current +// implementation falls back to getOrCreate to avoid crashing on +// yet-unhandled pointer expressions, creating an empty origin for them. +if (It == DeclToOriginID.end()) + return getOrCreate(D); + return It->second; } diff --git a/clang/test/Analysis/LifetimeSafety/CMakeLists.txt b/clang/test/Analysis/LifetimeSafety/CMakeLists.txt new file mode 100644 index 0..ce37a29655668 --- /dev/null +++ b/clang/test/Analysis/LifetimeSafety/CMakeLists.txt @@ -0,0 +1,49 @@ +# = +# Lifetime Analysis Benchmarking Target +# = +# This target allows running performance benchmarks for the clang lifetime analysis +# using a Python script (with managed dependencies). + +find_package(Python3 COMPONENTS Interpreter REQUIRED) + +# Define paths for the virtual environment and requirements file. +set(LIFETIME_BENCHMARK_SCRIPT + "${CMAKE_CURRENT_SOURCE_DIR}/benchmark.py") +set(LIFETIME_BENCHMARK_VENV_DIR "${CMAKE_CURRENT_BINARY_DIR}/benchmark-venv") +set(LIFETIME_BENCHMARK_REQUIREMENTS + "${CMAKE_CURRENT_SOURCE_DIR}/requirements.txt") +set(LIFETIME_BENCHMARK_OUTPUT_DIR + "${CMAKE_CURRENT_BINARY_DIR}/benchmark_results") + + +if(EXISTS ${LIFETIME_BENCHMARK_SCRIPT} AND EXISTS ${LIFETIME_BENCHMARK_REQUIREMENTS}) + + # Set up the virtual environment and install packages + add_custom_command( +OUTPUT ${LIFETIME_BENCHMARK_VENV_DIR}/pyvenv.cfg +COMMAND ${Python3_EXECUTABLE} -m venv ${LIFETIME_BENCHMARK_VENV_DIR} +COMMAND ${LIFETIME_BENCHMARK_VENV_DIR}/bin/python -m pip install -r ${LIFETIME_BENCHMARK_REQUIREMENTS} +DEPENDS ${LIFETIME_BENCHMARK_REQUIREMENTS} +COMMENT "Creating Python virtual environment and installing dependencies for benchmark..." + ) + add_custom_target(benchmark_venv_setup +DEPENDS ${LIFETIME_BENCHMARK_VENV_DIR}/pyvenv.cfg + ) + + # Main benchmark target + add_custom_target(benchmark_lifetime_safety_analysis +COMMAND ${LIFETIME_BENCHMARK_VENV_DIR}/bin/python ${LIFETIME_BENCHMARK_SCRIPT} +--clang-binary ${LLVM_BINARY_DIR}/bin/clang +--output-dir ${LIFETIME_BENCHMARK_OUTPUT_DIR} + +DEPENDS clang benchmark_venv_setup + +# Display the output directly in the console. +USES_TERMINAL + +COMMENT "Running Lifetime Analysis performance benchmarks..." + ) + + set_target_properties(benchmark_lifetime_safety_analysis +PROPERTIES FOLDER "Clang/Benchmarks") +endif() diff --git a/clang/test/Analysis/LifetimeSafety/benchmark.py b/clang/test/Analysis/LifetimeSafety/benchmark.py new file mode 100644 index 0..10ffa6d7dc2be --- /dev/null +++ b/clang/test/Analysis/LifetimeSafety/benchmark.py @@ -0,0 +1,308 @@ +import sys +import argparse +import subprocess +import tempfile +import json +import os +from datetime import datetime +import numpy as np +from scipy.optimize import curve_fit +from scipy.stats import t + + +def generate_cpp_cycle_test(n: int) -> str: +""" +Generates a C++ code snippet with a specified number of pointers in a cycle. +Creates a while loop that rotates N pointers. +This pattern tests the convergence speed of the dataflow analysis when +reaching its fixed point. + +Example: +struct MyObj { int id; ~MyObj() {} }; + +void long_cycle_4(bool condition) { +MyObj v1{1}; +MyObj v2{1}; +MyObj v3{1}; +MyObj v4{1}; + +MyObj* p1 = &v1; +MyObj* p2 = &v2; +MyObj* p3 = &v3; +MyObj* p4 = &v4; + +w
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/147315 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/147315 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/147315 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/147315 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/147315 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Implement dataflow analysis for loan propagation (PR #147295)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/147295 >From 8cc690f5cae252e744dc7244dc701929a44a8799 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Sun, 6 Jul 2025 19:12:55 + Subject: [PATCH] [LifetimeSafety] Propagate loans using dataflow analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 258 +- .../Sema/warn-lifetime-safety-dataflow.cpp| 186 + 2 files changed, 443 insertions(+), 1 deletion(-) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index 366e73e803146..1c83b5051bad1 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -13,7 +13,10 @@ #include "clang/Analysis/Analyses/PostOrderCFGView.h" #include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" +#include "clang/Analysis/FlowSensitive/DataflowWorklist.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/ImmutableSet.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Debug.h" @@ -487,7 +490,247 @@ class FactGenerator : public ConstStmtVisitor { }; // = // -// TODO: Run dataflow analysis to propagate loans, analyse and error reporting. +// The Dataflow Lattice +// = // + +// Using LLVM's immutable collections is efficient for dataflow analysis +// as it avoids deep copies during state transitions. +// TODO(opt): Consider using a bitset to represent the set of loans. +using LoanSet = llvm::ImmutableSet; +using OriginLoanMap = llvm::ImmutableMap; + +/// An object to hold the factories for immutable collections, ensuring +/// that all created states share the same underlying memory management. +struct LifetimeFactory { + OriginLoanMap::Factory OriginMapFact; + LoanSet::Factory LoanSetFact; + + LoanSet createLoanSet(LoanID LID) { +return LoanSetFact.add(LoanSetFact.getEmptySet(), LID); + } +}; + +/// LifetimeLattice represents the state of our analysis at a given program +/// point. It is an immutable object, and all operations produce a new +/// instance rather than modifying the existing one. +struct LifetimeLattice { + /// The map from an origin to the set of loans it contains. + /// TODO(opt): To reduce the lattice size, propagate origins of declarations, + /// not expressions, because expressions are not visible across blocks. + OriginLoanMap Origins = OriginLoanMap(nullptr); + + explicit LifetimeLattice(const OriginLoanMap &S) : Origins(S) {} + LifetimeLattice() = default; + + bool operator==(const LifetimeLattice &Other) const { +return Origins == Other.Origins; + } + bool operator!=(const LifetimeLattice &Other) const { +return !(*this == Other); + } + + LoanSet getLoans(OriginID OID, LifetimeFactory &Factory) const { +if (auto *Loans = Origins.lookup(OID)) + return *Loans; +return Factory.LoanSetFact.getEmptySet(); + } + + /// Computes the union of two lattices by performing a key-wise join of + /// their OriginLoanMaps. + // TODO(opt): This key-wise join is a performance bottleneck. A more + // efficient merge could be implemented using a Patricia Trie or HAMT + // instead of the current AVL-tree-based ImmutableMap. + LifetimeLattice join(const LifetimeLattice &Other, + LifetimeFactory &Factory) const { +/// Merge the smaller map into the larger one ensuring we iterate over the +/// smaller map. +if (Origins.getHeight() < Other.Origins.getHeight()) + return Other.join(*this, Factory); + +OriginLoanMap JoinedState = Origins; +// For each origin in the other map, union its loan set with ours. +for (const auto &Entry : Other.Origins) { + OriginID OID = Entry.first; + LoanSet OtherLoanSet = Entry.second; + JoinedState = Factory.OriginMapFact.add( + JoinedState, OID, + join(getLoans(OID, Factory), OtherLoanSet, Factory)); +} +return LifetimeLattice(JoinedState); + } + + LoanSet join(LoanSet a, LoanSet b, LifetimeFactory &Factory) const { +/// Merge the smaller set into the larger one ensuring we iterate over the +/// smaller set. +if (a.getHeight() < b.getHeight()) + std::swap(a, b); +LoanSet Result = a; +for (LoanID LID : b) { + /// TODO(opt): Profiling shows that this loop is a major performance + /// bottleneck. Investigate using a BitVector to represent the set of + /// loans for improved join performance. + Result = Factory.LoanSetFact.add(Result, LID); +} +return Result; + } + + void dump(llvm::raw_ostream &OS) const { +OS << "LifetimeLattice State:\n"; +if (Origins.isEmpty()) + OS << " \n"; +for (const auto &Entry : Origins) { + if (Entry.second.isEmpty()) +OS
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/147315 >From e8687c3d58a9da0874814846a1dbbaf173cdbf34 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 7 Jul 2025 15:13:00 + Subject: [PATCH] [LifetimeSafety] Add script performance benchmarking --- .../Analysis/LifetimeSafety/CMakeLists.txt| 49 +++ .../test/Analysis/LifetimeSafety/benchmark.py | 307 ++ .../Analysis/LifetimeSafety/requirements.txt | 2 + clang/test/CMakeLists.txt | 2 + 4 files changed, 360 insertions(+) create mode 100644 clang/test/Analysis/LifetimeSafety/CMakeLists.txt create mode 100644 clang/test/Analysis/LifetimeSafety/benchmark.py create mode 100644 clang/test/Analysis/LifetimeSafety/requirements.txt diff --git a/clang/test/Analysis/LifetimeSafety/CMakeLists.txt b/clang/test/Analysis/LifetimeSafety/CMakeLists.txt new file mode 100644 index 0..ce37a29655668 --- /dev/null +++ b/clang/test/Analysis/LifetimeSafety/CMakeLists.txt @@ -0,0 +1,49 @@ +# = +# Lifetime Analysis Benchmarking Target +# = +# This target allows running performance benchmarks for the clang lifetime analysis +# using a Python script (with managed dependencies). + +find_package(Python3 COMPONENTS Interpreter REQUIRED) + +# Define paths for the virtual environment and requirements file. +set(LIFETIME_BENCHMARK_SCRIPT + "${CMAKE_CURRENT_SOURCE_DIR}/benchmark.py") +set(LIFETIME_BENCHMARK_VENV_DIR "${CMAKE_CURRENT_BINARY_DIR}/benchmark-venv") +set(LIFETIME_BENCHMARK_REQUIREMENTS + "${CMAKE_CURRENT_SOURCE_DIR}/requirements.txt") +set(LIFETIME_BENCHMARK_OUTPUT_DIR + "${CMAKE_CURRENT_BINARY_DIR}/benchmark_results") + + +if(EXISTS ${LIFETIME_BENCHMARK_SCRIPT} AND EXISTS ${LIFETIME_BENCHMARK_REQUIREMENTS}) + + # Set up the virtual environment and install packages + add_custom_command( +OUTPUT ${LIFETIME_BENCHMARK_VENV_DIR}/pyvenv.cfg +COMMAND ${Python3_EXECUTABLE} -m venv ${LIFETIME_BENCHMARK_VENV_DIR} +COMMAND ${LIFETIME_BENCHMARK_VENV_DIR}/bin/python -m pip install -r ${LIFETIME_BENCHMARK_REQUIREMENTS} +DEPENDS ${LIFETIME_BENCHMARK_REQUIREMENTS} +COMMENT "Creating Python virtual environment and installing dependencies for benchmark..." + ) + add_custom_target(benchmark_venv_setup +DEPENDS ${LIFETIME_BENCHMARK_VENV_DIR}/pyvenv.cfg + ) + + # Main benchmark target + add_custom_target(benchmark_lifetime_safety_analysis +COMMAND ${LIFETIME_BENCHMARK_VENV_DIR}/bin/python ${LIFETIME_BENCHMARK_SCRIPT} +--clang-binary ${LLVM_BINARY_DIR}/bin/clang +--output-dir ${LIFETIME_BENCHMARK_OUTPUT_DIR} + +DEPENDS clang benchmark_venv_setup + +# Display the output directly in the console. +USES_TERMINAL + +COMMENT "Running Lifetime Analysis performance benchmarks..." + ) + + set_target_properties(benchmark_lifetime_safety_analysis +PROPERTIES FOLDER "Clang/Benchmarks") +endif() diff --git a/clang/test/Analysis/LifetimeSafety/benchmark.py b/clang/test/Analysis/LifetimeSafety/benchmark.py new file mode 100644 index 0..9d5f36c51b9ee --- /dev/null +++ b/clang/test/Analysis/LifetimeSafety/benchmark.py @@ -0,0 +1,307 @@ +import sys +import argparse +import subprocess +import tempfile +import json +import os +from datetime import datetime +import numpy as np +from scipy.optimize import curve_fit +from scipy.stats import t + + +def generate_cpp_cycle_test(n: int) -> str: +""" +Generates a C++ code snippet with a specified number of pointers in a cycle. +Creates a while loop that rotates N pointers. +This pattern tests the convergence speed of the dataflow analysis when +reaching its fixed point. + +Example: +struct MyObj { int id; ~MyObj() {} }; + +void long_cycle_4(bool condition) { +MyObj v1{1}; +MyObj v2{1}; +MyObj v3{1}; +MyObj v4{1}; + +MyObj* p1 = &v1; +MyObj* p2 = &v2; +MyObj* p3 = &v3; +MyObj* p4 = &v4; + +while (condition) { +MyObj* temp = p1; +p1 = p2; +p2 = p3; +p3 = p4; +p4 = temp; +} +} +""" +if n <= 0: +return "// Number of variables must be positive." + +cpp_code = "struct MyObj { int id; ~MyObj() {} };\n\n" +cpp_code += f"void long_cycle_{n}(bool condition) {{\n" +for i in range(1, n + 1): +cpp_code += f" MyObj v{i}{{1}};\n" +cpp_code += "\n" +for i in range(1, n + 1): +cpp_code += f" MyObj* p{i} = &v{i};\n" + +cpp_code += "\n while (condition) {\n" +if n > 0: +cpp_code += f"MyObj* temp = p1;\n" +for i in range(1, n): +cpp_code += f"p{i} = p{i+1};\n" +cpp_code += f"
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
https://github.com/usx95 ready_for_review https://github.com/llvm/llvm-project/pull/147315 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/147315 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/147315 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/147315 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/147315 >From 1ebcbdfa5dae7a9970634e8316f4b8e344312a0e Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 7 Jul 2025 15:13:00 + Subject: [PATCH] [LifetimeSafety] Add script performance benchmarking --- clang/lib/Analysis/LifetimeSafety.cpp | 7 +- .../Analysis/LifetimeSafety/CMakeLists.txt| 49 +++ .../test/Analysis/LifetimeSafety/benchmark.py | 307 ++ .../Analysis/LifetimeSafety/requirements.txt | 2 + clang/test/CMakeLists.txt | 2 + 5 files changed, 366 insertions(+), 1 deletion(-) create mode 100644 clang/test/Analysis/LifetimeSafety/CMakeLists.txt create mode 100644 clang/test/Analysis/LifetimeSafety/benchmark.py create mode 100644 clang/test/Analysis/LifetimeSafety/requirements.txt diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index e881e592ef59f..1c83b5051bad1 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -151,7 +151,12 @@ class OriginManager { OriginID get(const ValueDecl &D) { auto It = DeclToOriginID.find(&D); -assert(It != DeclToOriginID.end()); +// TODO: This should be an assert(It != ExprToOriginID.end()). The current +// implementation falls back to getOrCreate to avoid crashing on +// yet-unhandled pointer expressions, creating an empty origin for them. +if (It == DeclToOriginID.end()) + return getOrCreate(D); + return It->second; } diff --git a/clang/test/Analysis/LifetimeSafety/CMakeLists.txt b/clang/test/Analysis/LifetimeSafety/CMakeLists.txt new file mode 100644 index 0..ce37a29655668 --- /dev/null +++ b/clang/test/Analysis/LifetimeSafety/CMakeLists.txt @@ -0,0 +1,49 @@ +# = +# Lifetime Analysis Benchmarking Target +# = +# This target allows running performance benchmarks for the clang lifetime analysis +# using a Python script (with managed dependencies). + +find_package(Python3 COMPONENTS Interpreter REQUIRED) + +# Define paths for the virtual environment and requirements file. +set(LIFETIME_BENCHMARK_SCRIPT + "${CMAKE_CURRENT_SOURCE_DIR}/benchmark.py") +set(LIFETIME_BENCHMARK_VENV_DIR "${CMAKE_CURRENT_BINARY_DIR}/benchmark-venv") +set(LIFETIME_BENCHMARK_REQUIREMENTS + "${CMAKE_CURRENT_SOURCE_DIR}/requirements.txt") +set(LIFETIME_BENCHMARK_OUTPUT_DIR + "${CMAKE_CURRENT_BINARY_DIR}/benchmark_results") + + +if(EXISTS ${LIFETIME_BENCHMARK_SCRIPT} AND EXISTS ${LIFETIME_BENCHMARK_REQUIREMENTS}) + + # Set up the virtual environment and install packages + add_custom_command( +OUTPUT ${LIFETIME_BENCHMARK_VENV_DIR}/pyvenv.cfg +COMMAND ${Python3_EXECUTABLE} -m venv ${LIFETIME_BENCHMARK_VENV_DIR} +COMMAND ${LIFETIME_BENCHMARK_VENV_DIR}/bin/python -m pip install -r ${LIFETIME_BENCHMARK_REQUIREMENTS} +DEPENDS ${LIFETIME_BENCHMARK_REQUIREMENTS} +COMMENT "Creating Python virtual environment and installing dependencies for benchmark..." + ) + add_custom_target(benchmark_venv_setup +DEPENDS ${LIFETIME_BENCHMARK_VENV_DIR}/pyvenv.cfg + ) + + # Main benchmark target + add_custom_target(benchmark_lifetime_safety_analysis +COMMAND ${LIFETIME_BENCHMARK_VENV_DIR}/bin/python ${LIFETIME_BENCHMARK_SCRIPT} +--clang-binary ${LLVM_BINARY_DIR}/bin/clang +--output-dir ${LIFETIME_BENCHMARK_OUTPUT_DIR} + +DEPENDS clang benchmark_venv_setup + +# Display the output directly in the console. +USES_TERMINAL + +COMMENT "Running Lifetime Analysis performance benchmarks..." + ) + + set_target_properties(benchmark_lifetime_safety_analysis +PROPERTIES FOLDER "Clang/Benchmarks") +endif() diff --git a/clang/test/Analysis/LifetimeSafety/benchmark.py b/clang/test/Analysis/LifetimeSafety/benchmark.py new file mode 100644 index 0..9d5f36c51b9ee --- /dev/null +++ b/clang/test/Analysis/LifetimeSafety/benchmark.py @@ -0,0 +1,307 @@ +import sys +import argparse +import subprocess +import tempfile +import json +import os +from datetime import datetime +import numpy as np +from scipy.optimize import curve_fit +from scipy.stats import t + + +def generate_cpp_cycle_test(n: int) -> str: +""" +Generates a C++ code snippet with a specified number of pointers in a cycle. +Creates a while loop that rotates N pointers. +This pattern tests the convergence speed of the dataflow analysis when +reaching its fixed point. + +Example: +struct MyObj { int id; ~MyObj() {} }; + +void long_cycle_4(bool condition) { +MyObj v1{1}; +MyObj v2{1}; +MyObj v3{1}; +MyObj v4{1}; + +MyObj* p1 = &v1; +MyObj* p2 = &v2; +MyObj* p3 = &v3; +MyObj* p4 = &v4; + +w
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/147315 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/147315 >From 7d9009c2f22bf3f0980f7fd811be3185192490cf Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 7 Jul 2025 15:13:00 + Subject: [PATCH] [LifetimeSafety] Add script performance benchmarking --- .../Analysis/LifetimeSafety/CMakeLists.txt| 49 +++ .../test/Analysis/LifetimeSafety/benchmark.py | 307 ++ .../Analysis/LifetimeSafety/requirements.txt | 2 + clang/test/CMakeLists.txt | 2 + 4 files changed, 360 insertions(+) create mode 100644 clang/test/Analysis/LifetimeSafety/CMakeLists.txt create mode 100644 clang/test/Analysis/LifetimeSafety/benchmark.py create mode 100644 clang/test/Analysis/LifetimeSafety/requirements.txt diff --git a/clang/test/Analysis/LifetimeSafety/CMakeLists.txt b/clang/test/Analysis/LifetimeSafety/CMakeLists.txt new file mode 100644 index 0..ce37a29655668 --- /dev/null +++ b/clang/test/Analysis/LifetimeSafety/CMakeLists.txt @@ -0,0 +1,49 @@ +# = +# Lifetime Analysis Benchmarking Target +# = +# This target allows running performance benchmarks for the clang lifetime analysis +# using a Python script (with managed dependencies). + +find_package(Python3 COMPONENTS Interpreter REQUIRED) + +# Define paths for the virtual environment and requirements file. +set(LIFETIME_BENCHMARK_SCRIPT + "${CMAKE_CURRENT_SOURCE_DIR}/benchmark.py") +set(LIFETIME_BENCHMARK_VENV_DIR "${CMAKE_CURRENT_BINARY_DIR}/benchmark-venv") +set(LIFETIME_BENCHMARK_REQUIREMENTS + "${CMAKE_CURRENT_SOURCE_DIR}/requirements.txt") +set(LIFETIME_BENCHMARK_OUTPUT_DIR + "${CMAKE_CURRENT_BINARY_DIR}/benchmark_results") + + +if(EXISTS ${LIFETIME_BENCHMARK_SCRIPT} AND EXISTS ${LIFETIME_BENCHMARK_REQUIREMENTS}) + + # Set up the virtual environment and install packages + add_custom_command( +OUTPUT ${LIFETIME_BENCHMARK_VENV_DIR}/pyvenv.cfg +COMMAND ${Python3_EXECUTABLE} -m venv ${LIFETIME_BENCHMARK_VENV_DIR} +COMMAND ${LIFETIME_BENCHMARK_VENV_DIR}/bin/python -m pip install -r ${LIFETIME_BENCHMARK_REQUIREMENTS} +DEPENDS ${LIFETIME_BENCHMARK_REQUIREMENTS} +COMMENT "Creating Python virtual environment and installing dependencies for benchmark..." + ) + add_custom_target(benchmark_venv_setup +DEPENDS ${LIFETIME_BENCHMARK_VENV_DIR}/pyvenv.cfg + ) + + # Main benchmark target + add_custom_target(benchmark_lifetime_safety_analysis +COMMAND ${LIFETIME_BENCHMARK_VENV_DIR}/bin/python ${LIFETIME_BENCHMARK_SCRIPT} +--clang-binary ${LLVM_BINARY_DIR}/bin/clang +--output-dir ${LIFETIME_BENCHMARK_OUTPUT_DIR} + +DEPENDS clang benchmark_venv_setup + +# Display the output directly in the console. +USES_TERMINAL + +COMMENT "Running Lifetime Analysis performance benchmarks..." + ) + + set_target_properties(benchmark_lifetime_safety_analysis +PROPERTIES FOLDER "Clang/Benchmarks") +endif() diff --git a/clang/test/Analysis/LifetimeSafety/benchmark.py b/clang/test/Analysis/LifetimeSafety/benchmark.py new file mode 100644 index 0..9d5f36c51b9ee --- /dev/null +++ b/clang/test/Analysis/LifetimeSafety/benchmark.py @@ -0,0 +1,307 @@ +import sys +import argparse +import subprocess +import tempfile +import json +import os +from datetime import datetime +import numpy as np +from scipy.optimize import curve_fit +from scipy.stats import t + + +def generate_cpp_cycle_test(n: int) -> str: +""" +Generates a C++ code snippet with a specified number of pointers in a cycle. +Creates a while loop that rotates N pointers. +This pattern tests the convergence speed of the dataflow analysis when +reaching its fixed point. + +Example: +struct MyObj { int id; ~MyObj() {} }; + +void long_cycle_4(bool condition) { +MyObj v1{1}; +MyObj v2{1}; +MyObj v3{1}; +MyObj v4{1}; + +MyObj* p1 = &v1; +MyObj* p2 = &v2; +MyObj* p3 = &v3; +MyObj* p4 = &v4; + +while (condition) { +MyObj* temp = p1; +p1 = p2; +p2 = p3; +p3 = p4; +p4 = temp; +} +} +""" +if n <= 0: +return "// Number of variables must be positive." + +cpp_code = "struct MyObj { int id; ~MyObj() {} };\n\n" +cpp_code += f"void long_cycle_{n}(bool condition) {{\n" +for i in range(1, n + 1): +cpp_code += f" MyObj v{i}{{1}};\n" +cpp_code += "\n" +for i in range(1, n + 1): +cpp_code += f" MyObj* p{i} = &v{i};\n" + +cpp_code += "\n while (condition) {\n" +if n > 0: +cpp_code += f"MyObj* temp = p1;\n" +for i in range(1, n): +cpp_code += f"p{i} = p{i+1};\n" +cpp_code += f"
[llvm-branch-commits] [clang] [LifetimeSafety] Add expired loans analysis (PR #148222)
https://github.com/usx95 created https://github.com/llvm/llvm-project/pull/148222 None >From 14a9c8b50df11ce48ce15d0fbe29568b3e23b5a6 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Fri, 11 Jul 2025 11:11:47 + Subject: [PATCH] [LifetimeSafety] Add expired loans analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 140 ++ 1 file changed, 140 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index e72192aa92c1a..88ec70d000d2c 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -735,6 +735,142 @@ class LifetimeDataflow { } }; +// = // +// Expired Loans Analysis +// = // + +/// The lattice for tracking expired loans. It is a set of loan IDs. +struct ExpiredLattice { + LoanSet Expired; + + ExpiredLattice() = default; + explicit ExpiredLattice(LoanSet S) : Expired(S) {} + + bool operator==(const ExpiredLattice &Other) const { +return Expired == Other.Expired; + } + bool operator!=(const ExpiredLattice &Other) const { +return !(*this == Other); + } + + /// Computes the union of two lattices. + ExpiredLattice join(const ExpiredLattice &Other, + LoanSet::Factory &Factory) const { +LoanSet JoinedSet = Expired; +for (LoanID LID : Other.Expired) + JoinedSet = Factory.add(JoinedSet, LID); +return ExpiredLattice(JoinedSet); + } + + void dump(llvm::raw_ostream &OS) const { +OS << "ExpiredLattice State:\n"; +if (Expired.isEmpty()) + OS << " \n"; +for (const LoanID &LID : Expired) + OS << " Loan " << LID << " is expired\n"; + } +}; + +/// Transfer function for the expired loans analysis. +class ExpiredLoansTransferer { + FactManager &AllFacts; + LoanSet::Factory &SetFactory; + +public: + explicit ExpiredLoansTransferer(FactManager &F, LoanSet::Factory &SF) + : AllFacts(F), SetFactory(SF) {} + + /// Computes the exit state of a block by applying all its facts sequentially + /// to a given entry state. + ExpiredLattice transferBlock(const CFGBlock *Block, +ExpiredLattice EntryState) { +ExpiredLattice BlockState = EntryState; +llvm::ArrayRef Facts = AllFacts.getFacts(Block); + +for (const Fact *F : Facts) { + BlockState = transferFact(BlockState, F); +} +return BlockState; + } + +private: + ExpiredLattice transferFact(ExpiredLattice In, const Fact *F) { +if (const auto *EF = F->getAs()) + return ExpiredLattice(SetFactory.add(In.Expired, EF->getLoanID())); + +if (const auto *IF = F->getAs()) + return ExpiredLattice(SetFactory.remove(In.Expired, IF->getLoanID())); + +return In; + } +}; + +/// Dataflow analysis driver for tracking expired loans. +class ExpiredLoansAnalysis { + const CFG &Cfg; + AnalysisDeclContext &AC; + LoanSet::Factory SetFactory; + ExpiredLoansTransferer Xfer; + + llvm::DenseMap BlockEntryStates; + llvm::DenseMap BlockExitStates; + +public: + ExpiredLoansAnalysis(const CFG &C, FactManager &FS, AnalysisDeclContext &AC) + : Cfg(C), AC(AC), Xfer(FS, SetFactory) {} + + void run() { +llvm::TimeTraceScope TimeProfile("Expired Loans Analysis"); +ForwardDataflowWorklist Worklist(Cfg, AC); +const CFGBlock *Entry = &Cfg.getEntry(); +BlockEntryStates[Entry] = ExpiredLattice(SetFactory.getEmptySet()); +Worklist.enqueueBlock(Entry); +while (const CFGBlock *B = Worklist.dequeue()) { + ExpiredLattice EntryState = getEntryState(B); + ExpiredLattice ExitState = Xfer.transferBlock(B, EntryState); + BlockExitStates[B] = ExitState; + + for (const CFGBlock *Successor : B->succs()) { +auto SuccIt = BlockEntryStates.find(Successor); +ExpiredLattice OldSuccEntryState = (SuccIt != BlockEntryStates.end()) +? SuccIt->second +: ExpiredLattice{}; +ExpiredLattice NewSuccEntryState = +OldSuccEntryState.join(ExitState, SetFactory); +if (SuccIt == BlockEntryStates.end() || +NewSuccEntryState != OldSuccEntryState) { + BlockEntryStates[Successor] = NewSuccEntryState; + Worklist.enqueueBlock(Successor); +} + } +} + } + + void dump() const { +llvm::dbgs() << "==\n"; +llvm::dbgs() << " Expired Loans Results:\n"; +llvm::dbgs() << "==\n"; +const CFGBlock &B = Cfg.getExit(); +getExitState(&B).dump(llvm::dbgs()); + } + + ExpiredLattice getEntryState(const CFGBlock *B) const { +auto It = BlockEntryStates.find(B); +if (It != BlockEntryStates.end()) { + return It->second; +} +return ExpiredLattice(SetFac
[llvm-branch-commits] [clang] [LifetimeSafety] Add expired loans analysis (PR #148222)
usx95 wrote: > [!WARNING] > This pull request is not mergeable via GitHub because a downstack PR is > open. Once all requirements are satisfied, merge this PR as a stack href="https://app.graphite.dev/github/pr/llvm/llvm-project/148222?utm_source=stack-comment-downstack-mergeability-warning"; > >on Graphite. > https://graphite.dev/docs/merge-pull-requests";>Learn more * **#148222** https://app.graphite.dev/github/pr/llvm/llvm-project/148222?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> 👈 https://app.graphite.dev/github/pr/llvm/llvm-project/148222?utm_source=stack-comment-view-in-graphite"; target="_blank">(View in Graphite) * **#148065** https://app.graphite.dev/github/pr/llvm/llvm-project/148065?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>: 1 other dependent PR ([#147315](https://github.com/llvm/llvm-project/pull/147315) https://app.graphite.dev/github/pr/llvm/llvm-project/147315?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/>) * `main` This stack of pull requests is managed by https://graphite.dev?utm-source=stack-comment";>Graphite. Learn more about https://stacking.dev/?utm_source=stack-comment";>stacking. https://github.com/llvm/llvm-project/pull/148222 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/147315 >From 7fcb14746ba080092560f18860534bb4d2d7adda Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 7 Jul 2025 15:13:00 + Subject: [PATCH] [LifetimeSafety] Add script performance benchmarking --- .../Analysis/LifetimeSafety/CMakeLists.txt| 49 +++ .../test/Analysis/LifetimeSafety/benchmark.py | 307 ++ .../Analysis/LifetimeSafety/requirements.txt | 2 + clang/test/CMakeLists.txt | 2 + 4 files changed, 360 insertions(+) create mode 100644 clang/test/Analysis/LifetimeSafety/CMakeLists.txt create mode 100644 clang/test/Analysis/LifetimeSafety/benchmark.py create mode 100644 clang/test/Analysis/LifetimeSafety/requirements.txt diff --git a/clang/test/Analysis/LifetimeSafety/CMakeLists.txt b/clang/test/Analysis/LifetimeSafety/CMakeLists.txt new file mode 100644 index 0..ce37a29655668 --- /dev/null +++ b/clang/test/Analysis/LifetimeSafety/CMakeLists.txt @@ -0,0 +1,49 @@ +# = +# Lifetime Analysis Benchmarking Target +# = +# This target allows running performance benchmarks for the clang lifetime analysis +# using a Python script (with managed dependencies). + +find_package(Python3 COMPONENTS Interpreter REQUIRED) + +# Define paths for the virtual environment and requirements file. +set(LIFETIME_BENCHMARK_SCRIPT + "${CMAKE_CURRENT_SOURCE_DIR}/benchmark.py") +set(LIFETIME_BENCHMARK_VENV_DIR "${CMAKE_CURRENT_BINARY_DIR}/benchmark-venv") +set(LIFETIME_BENCHMARK_REQUIREMENTS + "${CMAKE_CURRENT_SOURCE_DIR}/requirements.txt") +set(LIFETIME_BENCHMARK_OUTPUT_DIR + "${CMAKE_CURRENT_BINARY_DIR}/benchmark_results") + + +if(EXISTS ${LIFETIME_BENCHMARK_SCRIPT} AND EXISTS ${LIFETIME_BENCHMARK_REQUIREMENTS}) + + # Set up the virtual environment and install packages + add_custom_command( +OUTPUT ${LIFETIME_BENCHMARK_VENV_DIR}/pyvenv.cfg +COMMAND ${Python3_EXECUTABLE} -m venv ${LIFETIME_BENCHMARK_VENV_DIR} +COMMAND ${LIFETIME_BENCHMARK_VENV_DIR}/bin/python -m pip install -r ${LIFETIME_BENCHMARK_REQUIREMENTS} +DEPENDS ${LIFETIME_BENCHMARK_REQUIREMENTS} +COMMENT "Creating Python virtual environment and installing dependencies for benchmark..." + ) + add_custom_target(benchmark_venv_setup +DEPENDS ${LIFETIME_BENCHMARK_VENV_DIR}/pyvenv.cfg + ) + + # Main benchmark target + add_custom_target(benchmark_lifetime_safety_analysis +COMMAND ${LIFETIME_BENCHMARK_VENV_DIR}/bin/python ${LIFETIME_BENCHMARK_SCRIPT} +--clang-binary ${LLVM_BINARY_DIR}/bin/clang +--output-dir ${LIFETIME_BENCHMARK_OUTPUT_DIR} + +DEPENDS clang benchmark_venv_setup + +# Display the output directly in the console. +USES_TERMINAL + +COMMENT "Running Lifetime Analysis performance benchmarks..." + ) + + set_target_properties(benchmark_lifetime_safety_analysis +PROPERTIES FOLDER "Clang/Benchmarks") +endif() diff --git a/clang/test/Analysis/LifetimeSafety/benchmark.py b/clang/test/Analysis/LifetimeSafety/benchmark.py new file mode 100644 index 0..9d5f36c51b9ee --- /dev/null +++ b/clang/test/Analysis/LifetimeSafety/benchmark.py @@ -0,0 +1,307 @@ +import sys +import argparse +import subprocess +import tempfile +import json +import os +from datetime import datetime +import numpy as np +from scipy.optimize import curve_fit +from scipy.stats import t + + +def generate_cpp_cycle_test(n: int) -> str: +""" +Generates a C++ code snippet with a specified number of pointers in a cycle. +Creates a while loop that rotates N pointers. +This pattern tests the convergence speed of the dataflow analysis when +reaching its fixed point. + +Example: +struct MyObj { int id; ~MyObj() {} }; + +void long_cycle_4(bool condition) { +MyObj v1{1}; +MyObj v2{1}; +MyObj v3{1}; +MyObj v4{1}; + +MyObj* p1 = &v1; +MyObj* p2 = &v2; +MyObj* p3 = &v3; +MyObj* p4 = &v4; + +while (condition) { +MyObj* temp = p1; +p1 = p2; +p2 = p3; +p3 = p4; +p4 = temp; +} +} +""" +if n <= 0: +return "// Number of variables must be positive." + +cpp_code = "struct MyObj { int id; ~MyObj() {} };\n\n" +cpp_code += f"void long_cycle_{n}(bool condition) {{\n" +for i in range(1, n + 1): +cpp_code += f" MyObj v{i}{{1}};\n" +cpp_code += "\n" +for i in range(1, n + 1): +cpp_code += f" MyObj* p{i} = &v{i};\n" + +cpp_code += "\n while (condition) {\n" +if n > 0: +cpp_code += f"MyObj* temp = p1;\n" +for i in range(1, n): +cpp_code += f"p{i} = p{i+1};\n" +cpp_code += f"
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/147315 >From 7fcb14746ba080092560f18860534bb4d2d7adda Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 7 Jul 2025 15:13:00 + Subject: [PATCH] [LifetimeSafety] Add script performance benchmarking --- .../Analysis/LifetimeSafety/CMakeLists.txt| 49 +++ .../test/Analysis/LifetimeSafety/benchmark.py | 307 ++ .../Analysis/LifetimeSafety/requirements.txt | 2 + clang/test/CMakeLists.txt | 2 + 4 files changed, 360 insertions(+) create mode 100644 clang/test/Analysis/LifetimeSafety/CMakeLists.txt create mode 100644 clang/test/Analysis/LifetimeSafety/benchmark.py create mode 100644 clang/test/Analysis/LifetimeSafety/requirements.txt diff --git a/clang/test/Analysis/LifetimeSafety/CMakeLists.txt b/clang/test/Analysis/LifetimeSafety/CMakeLists.txt new file mode 100644 index 0..ce37a29655668 --- /dev/null +++ b/clang/test/Analysis/LifetimeSafety/CMakeLists.txt @@ -0,0 +1,49 @@ +# = +# Lifetime Analysis Benchmarking Target +# = +# This target allows running performance benchmarks for the clang lifetime analysis +# using a Python script (with managed dependencies). + +find_package(Python3 COMPONENTS Interpreter REQUIRED) + +# Define paths for the virtual environment and requirements file. +set(LIFETIME_BENCHMARK_SCRIPT + "${CMAKE_CURRENT_SOURCE_DIR}/benchmark.py") +set(LIFETIME_BENCHMARK_VENV_DIR "${CMAKE_CURRENT_BINARY_DIR}/benchmark-venv") +set(LIFETIME_BENCHMARK_REQUIREMENTS + "${CMAKE_CURRENT_SOURCE_DIR}/requirements.txt") +set(LIFETIME_BENCHMARK_OUTPUT_DIR + "${CMAKE_CURRENT_BINARY_DIR}/benchmark_results") + + +if(EXISTS ${LIFETIME_BENCHMARK_SCRIPT} AND EXISTS ${LIFETIME_BENCHMARK_REQUIREMENTS}) + + # Set up the virtual environment and install packages + add_custom_command( +OUTPUT ${LIFETIME_BENCHMARK_VENV_DIR}/pyvenv.cfg +COMMAND ${Python3_EXECUTABLE} -m venv ${LIFETIME_BENCHMARK_VENV_DIR} +COMMAND ${LIFETIME_BENCHMARK_VENV_DIR}/bin/python -m pip install -r ${LIFETIME_BENCHMARK_REQUIREMENTS} +DEPENDS ${LIFETIME_BENCHMARK_REQUIREMENTS} +COMMENT "Creating Python virtual environment and installing dependencies for benchmark..." + ) + add_custom_target(benchmark_venv_setup +DEPENDS ${LIFETIME_BENCHMARK_VENV_DIR}/pyvenv.cfg + ) + + # Main benchmark target + add_custom_target(benchmark_lifetime_safety_analysis +COMMAND ${LIFETIME_BENCHMARK_VENV_DIR}/bin/python ${LIFETIME_BENCHMARK_SCRIPT} +--clang-binary ${LLVM_BINARY_DIR}/bin/clang +--output-dir ${LIFETIME_BENCHMARK_OUTPUT_DIR} + +DEPENDS clang benchmark_venv_setup + +# Display the output directly in the console. +USES_TERMINAL + +COMMENT "Running Lifetime Analysis performance benchmarks..." + ) + + set_target_properties(benchmark_lifetime_safety_analysis +PROPERTIES FOLDER "Clang/Benchmarks") +endif() diff --git a/clang/test/Analysis/LifetimeSafety/benchmark.py b/clang/test/Analysis/LifetimeSafety/benchmark.py new file mode 100644 index 0..9d5f36c51b9ee --- /dev/null +++ b/clang/test/Analysis/LifetimeSafety/benchmark.py @@ -0,0 +1,307 @@ +import sys +import argparse +import subprocess +import tempfile +import json +import os +from datetime import datetime +import numpy as np +from scipy.optimize import curve_fit +from scipy.stats import t + + +def generate_cpp_cycle_test(n: int) -> str: +""" +Generates a C++ code snippet with a specified number of pointers in a cycle. +Creates a while loop that rotates N pointers. +This pattern tests the convergence speed of the dataflow analysis when +reaching its fixed point. + +Example: +struct MyObj { int id; ~MyObj() {} }; + +void long_cycle_4(bool condition) { +MyObj v1{1}; +MyObj v2{1}; +MyObj v3{1}; +MyObj v4{1}; + +MyObj* p1 = &v1; +MyObj* p2 = &v2; +MyObj* p3 = &v3; +MyObj* p4 = &v4; + +while (condition) { +MyObj* temp = p1; +p1 = p2; +p2 = p3; +p3 = p4; +p4 = temp; +} +} +""" +if n <= 0: +return "// Number of variables must be positive." + +cpp_code = "struct MyObj { int id; ~MyObj() {} };\n\n" +cpp_code += f"void long_cycle_{n}(bool condition) {{\n" +for i in range(1, n + 1): +cpp_code += f" MyObj v{i}{{1}};\n" +cpp_code += "\n" +for i in range(1, n + 1): +cpp_code += f" MyObj* p{i} = &v{i};\n" + +cpp_code += "\n while (condition) {\n" +if n > 0: +cpp_code += f"MyObj* temp = p1;\n" +for i in range(1, n): +cpp_code += f"p{i} = p{i+1};\n" +cpp_code += f"
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
usx95 wrote: > [!WARNING] > This pull request is not mergeable via GitHub because a downstack PR is > open. Once all requirements are satisfied, merge this PR as a stack href="https://app.graphite.dev/github/pr/llvm/llvm-project/147315?utm_source=stack-comment-downstack-mergeability-warning"; > >on Graphite. > https://graphite.dev/docs/merge-pull-requests";>Learn more * **#147315** https://app.graphite.dev/github/pr/llvm/llvm-project/147315?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> 👈 https://app.graphite.dev/github/pr/llvm/llvm-project/147315?utm_source=stack-comment-view-in-graphite"; target="_blank">(View in Graphite) * **#147295** https://app.graphite.dev/github/pr/llvm/llvm-project/147295?utm_source=stack-comment-icon"; target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" width="10px" height="10px"/> * `users/usx95/lifetime-safety-initial` This stack of pull requests is managed by https://graphite.dev?utm-source=stack-comment";>Graphite. Learn more about https://stacking.dev/?utm_source=stack-comment";>stacking. https://github.com/llvm/llvm-project/pull/147315 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Implement dataflow analysis for loan propagation (PR #147295)
usx95 wrote: Sorry about closing this. I have moved this to https://github.com/llvm/llvm-project/pull/148065 I accidentally deleted the base branch which permanently closes the PR :( https://github.com/llvm/llvm-project/pull/147295 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add loan expiry analysis (PR #148712)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148712 >From 8f6394b2ab6183fd06f6e216cbaa70b823809e5d Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:32:35 + Subject: [PATCH 1/2] users/usx95/lifetime-safety-add-loan-expiry >From 12e5b9a2dc200a9d8e710ef509bb39021fc92de0 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:37:49 + Subject: [PATCH 2/2] [LifetimeSafety] Add loan expiry analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 61 +++ 1 file changed, 61 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index 0b4241cdf404c..300cc6ddd66af 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -769,6 +769,65 @@ class LoanPropagationAnalysis } }; +// = // +// Expired Loans Analysis +// = // + +/// The dataflow lattice for tracking the set of expired loans. +class ExpiredLattice { +public: + LoanSet Expired; + + ExpiredLattice() : Expired(nullptr) {}; + explicit ExpiredLattice(LoanSet S) : Expired(S) {} + + bool operator==(const ExpiredLattice &Other) const { +return Expired == Other.Expired; + } + bool operator!=(const ExpiredLattice &Other) const { +return !(*this == Other); + } + + void dump(llvm::raw_ostream &OS) const { +OS << "ExpiredLattice State:\n"; +if (Expired.isEmpty()) + OS << " \n"; +for (const LoanID &LID : Expired) + OS << " Loan " << LID << " is expired\n"; + } +}; + +/// The analysis that tracks which loans have expired. +class ExpiredLoansAnalysis +: public DataflowAnalysis { + + LoanSet::Factory &Factory; + +public: + ExpiredLoansAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, + LifetimeFactory &SF) + : DataflowAnalysis(C, AC, F), Factory(SF.LoanSetFactory) {} + + using DataflowAnalysis::transfer; + + const char *getAnalysisName() const { return "ExpiredLoans"; } + + Lattice getInitialState() { return Lattice(Factory.getEmptySet()); } + + /// Merges two lattices by taking the union of the expired loan sets. + Lattice join(Lattice L1, Lattice L2) const { +return Lattice(utils::join(L1.Expired, L2.Expired, Factory)); + } + + Lattice transfer(Lattice In, const ExpireFact &F) { +return Lattice(Factory.add(In.Expired, F.getLoanID())); + } + + Lattice transfer(Lattice In, const IssueFact &F) { +return Lattice(Factory.remove(In.Expired, F.getLoanID())); + } +}; + // = // // TODO: // - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)` @@ -801,5 +860,7 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg, LoanPropagationAnalysis LoanPropagation(Cfg, AC, FactMgr, Factory); LoanPropagation.run(); DEBUG_WITH_TYPE("LifetimeLoanPropagation", LoanPropagation.dump()); + + ExpiredLoansAnalysis ExpiredAnalysis(Cfg, AC, FactMgr, Factory); } } // namespace clang ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add loan expiry analysis (PR #148712)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148712 >From 3c30a13f6f796fd9483f7d6aeea28c12b8ad6d64 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:32:35 + Subject: [PATCH 1/2] users/usx95/lifetime-safety-add-loan-expiry >From 9da8f3ab473378b2f5191c88b60a847e777ef4ec Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:37:49 + Subject: [PATCH 2/2] [LifetimeSafety] Add loan expiry analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 61 +++ 1 file changed, 61 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index 8be93bbba7131..e30e979bf1120 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -762,6 +762,64 @@ class LoanPropagationAnalysis } }; +// = // +// Expired Loans Analysis +// = // + +/// The dataflow lattice for tracking the set of expired loans. +struct ExpiredLattice { + LoanSet Expired; + + ExpiredLattice() : Expired(nullptr) {}; + explicit ExpiredLattice(LoanSet S) : Expired(S) {} + + bool operator==(const ExpiredLattice &Other) const { +return Expired == Other.Expired; + } + bool operator!=(const ExpiredLattice &Other) const { +return !(*this == Other); + } + + void dump(llvm::raw_ostream &OS) const { +OS << "ExpiredLattice State:\n"; +if (Expired.isEmpty()) + OS << " \n"; +for (const LoanID &LID : Expired) + OS << " Loan " << LID << " is expired\n"; + } +}; + +/// The analysis that tracks which loans have expired. +class ExpiredLoansAnalysis +: public DataflowAnalysis { + + LoanSet::Factory &Factory; + +public: + ExpiredLoansAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, + LifetimeFactory &SF) + : DataflowAnalysis(C, AC, F), Factory(SF.LoanSetFactory) {} + + using DataflowAnalysis::transfer; + + StringRef getAnalysisName() const { return "ExpiredLoans"; } + + Lattice getInitialState() { return Lattice(Factory.getEmptySet()); } + + /// Merges two lattices by taking the union of the expired loan sets. + Lattice join(Lattice L1, Lattice L2) const { +return Lattice(utils::join(L1.Expired, L2.Expired, Factory)); + } + + Lattice transfer(Lattice In, const ExpireFact &F) { +return Lattice(Factory.add(In.Expired, F.getLoanID())); + } + + Lattice transfer(Lattice In, const IssueFact &F) { +return Lattice(Factory.remove(In.Expired, F.getLoanID())); + } +}; + // = // // TODO: // - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)` @@ -794,5 +852,8 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg, LoanPropagationAnalysis LoanPropagation(Cfg, AC, FactMgr, Factory); LoanPropagation.run(); DEBUG_WITH_TYPE("LifetimeLoanPropagation", LoanPropagation.dump()); + + ExpiredLoansAnalysis ExpiredLoans(Cfg, AC, FactMgr, Factory); + ExpiredLoans.run(); } } // namespace clang ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add loan expiry analysis (PR #148712)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148712 >From 3c30a13f6f796fd9483f7d6aeea28c12b8ad6d64 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:32:35 + Subject: [PATCH 1/2] users/usx95/lifetime-safety-add-loan-expiry >From 9da8f3ab473378b2f5191c88b60a847e777ef4ec Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:37:49 + Subject: [PATCH 2/2] [LifetimeSafety] Add loan expiry analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 61 +++ 1 file changed, 61 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index 8be93bbba7131..e30e979bf1120 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -762,6 +762,64 @@ class LoanPropagationAnalysis } }; +// = // +// Expired Loans Analysis +// = // + +/// The dataflow lattice for tracking the set of expired loans. +struct ExpiredLattice { + LoanSet Expired; + + ExpiredLattice() : Expired(nullptr) {}; + explicit ExpiredLattice(LoanSet S) : Expired(S) {} + + bool operator==(const ExpiredLattice &Other) const { +return Expired == Other.Expired; + } + bool operator!=(const ExpiredLattice &Other) const { +return !(*this == Other); + } + + void dump(llvm::raw_ostream &OS) const { +OS << "ExpiredLattice State:\n"; +if (Expired.isEmpty()) + OS << " \n"; +for (const LoanID &LID : Expired) + OS << " Loan " << LID << " is expired\n"; + } +}; + +/// The analysis that tracks which loans have expired. +class ExpiredLoansAnalysis +: public DataflowAnalysis { + + LoanSet::Factory &Factory; + +public: + ExpiredLoansAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, + LifetimeFactory &SF) + : DataflowAnalysis(C, AC, F), Factory(SF.LoanSetFactory) {} + + using DataflowAnalysis::transfer; + + StringRef getAnalysisName() const { return "ExpiredLoans"; } + + Lattice getInitialState() { return Lattice(Factory.getEmptySet()); } + + /// Merges two lattices by taking the union of the expired loan sets. + Lattice join(Lattice L1, Lattice L2) const { +return Lattice(utils::join(L1.Expired, L2.Expired, Factory)); + } + + Lattice transfer(Lattice In, const ExpireFact &F) { +return Lattice(Factory.add(In.Expired, F.getLoanID())); + } + + Lattice transfer(Lattice In, const IssueFact &F) { +return Lattice(Factory.remove(In.Expired, F.getLoanID())); + } +}; + // = // // TODO: // - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)` @@ -794,5 +852,8 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg, LoanPropagationAnalysis LoanPropagation(Cfg, AC, FactMgr, Factory); LoanPropagation.run(); DEBUG_WITH_TYPE("LifetimeLoanPropagation", LoanPropagation.dump()); + + ExpiredLoansAnalysis ExpiredLoans(Cfg, AC, FactMgr, Factory); + ExpiredLoans.run(); } } // namespace clang ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add loan expiry analysis (PR #148712)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148712 >From 542bc99c1f5fb5fc28a3374f61b2fa3d059d9d75 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:32:35 + Subject: [PATCH 1/2] users/usx95/lifetime-safety-add-loan-expiry >From 4b70fcf7f20083a34a18bf0f84dfc29cce696db4 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:37:49 + Subject: [PATCH 2/2] [LifetimeSafety] Add loan expiry analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 61 +++ 1 file changed, 61 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index 9d1b662e3c589..5e54e8dadcfd0 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -763,6 +763,65 @@ class LoanPropagationAnalysis } }; +// = // +// Expired Loans Analysis +// = // + +/// The dataflow lattice for tracking the set of expired loans. +class ExpiredLattice { +public: + LoanSet Expired; + + ExpiredLattice() : Expired(nullptr) {}; + explicit ExpiredLattice(LoanSet S) : Expired(S) {} + + bool operator==(const ExpiredLattice &Other) const { +return Expired == Other.Expired; + } + bool operator!=(const ExpiredLattice &Other) const { +return !(*this == Other); + } + + void dump(llvm::raw_ostream &OS) const { +OS << "ExpiredLattice State:\n"; +if (Expired.isEmpty()) + OS << " \n"; +for (const LoanID &LID : Expired) + OS << " Loan " << LID << " is expired\n"; + } +}; + +/// The analysis that tracks which loans have expired. +class ExpiredLoansAnalysis +: public DataflowAnalysis { + + LoanSet::Factory &Factory; + +public: + ExpiredLoansAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, + LifetimeFactory &SF) + : DataflowAnalysis(C, AC, F), Factory(SF.LoanSetFactory) {} + + using DataflowAnalysis::transfer; + + const char *getAnalysisName() const { return "ExpiredLoans"; } + + Lattice getInitialState() { return Lattice(Factory.getEmptySet()); } + + /// Merges two lattices by taking the union of the expired loan sets. + Lattice join(Lattice L1, Lattice L2) const { +return Lattice(utils::join(L1.Expired, L2.Expired, Factory)); + } + + Lattice transfer(Lattice In, const ExpireFact &F) { +return Lattice(Factory.add(In.Expired, F.getLoanID())); + } + + Lattice transfer(Lattice In, const IssueFact &F) { +return Lattice(Factory.remove(In.Expired, F.getLoanID())); + } +}; + // = // // TODO: // - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)` @@ -795,5 +854,7 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg, LoanPropagationAnalysis LoanPropagation(Cfg, AC, FactMgr, Factory); LoanPropagation.run(); DEBUG_WITH_TYPE("LifetimeLoanPropagation", LoanPropagation.dump()); + + ExpiredLoansAnalysis ExpiredAnalysis(Cfg, AC, FactMgr, Factory); } } // namespace clang ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add loan expiry analysis (PR #148712)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148712 >From 542bc99c1f5fb5fc28a3374f61b2fa3d059d9d75 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:32:35 + Subject: [PATCH 1/2] users/usx95/lifetime-safety-add-loan-expiry >From 4b70fcf7f20083a34a18bf0f84dfc29cce696db4 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:37:49 + Subject: [PATCH 2/2] [LifetimeSafety] Add loan expiry analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 61 +++ 1 file changed, 61 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index 9d1b662e3c589..5e54e8dadcfd0 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -763,6 +763,65 @@ class LoanPropagationAnalysis } }; +// = // +// Expired Loans Analysis +// = // + +/// The dataflow lattice for tracking the set of expired loans. +class ExpiredLattice { +public: + LoanSet Expired; + + ExpiredLattice() : Expired(nullptr) {}; + explicit ExpiredLattice(LoanSet S) : Expired(S) {} + + bool operator==(const ExpiredLattice &Other) const { +return Expired == Other.Expired; + } + bool operator!=(const ExpiredLattice &Other) const { +return !(*this == Other); + } + + void dump(llvm::raw_ostream &OS) const { +OS << "ExpiredLattice State:\n"; +if (Expired.isEmpty()) + OS << " \n"; +for (const LoanID &LID : Expired) + OS << " Loan " << LID << " is expired\n"; + } +}; + +/// The analysis that tracks which loans have expired. +class ExpiredLoansAnalysis +: public DataflowAnalysis { + + LoanSet::Factory &Factory; + +public: + ExpiredLoansAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, + LifetimeFactory &SF) + : DataflowAnalysis(C, AC, F), Factory(SF.LoanSetFactory) {} + + using DataflowAnalysis::transfer; + + const char *getAnalysisName() const { return "ExpiredLoans"; } + + Lattice getInitialState() { return Lattice(Factory.getEmptySet()); } + + /// Merges two lattices by taking the union of the expired loan sets. + Lattice join(Lattice L1, Lattice L2) const { +return Lattice(utils::join(L1.Expired, L2.Expired, Factory)); + } + + Lattice transfer(Lattice In, const ExpireFact &F) { +return Lattice(Factory.add(In.Expired, F.getLoanID())); + } + + Lattice transfer(Lattice In, const IssueFact &F) { +return Lattice(Factory.remove(In.Expired, F.getLoanID())); + } +}; + // = // // TODO: // - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)` @@ -795,5 +854,7 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg, LoanPropagationAnalysis LoanPropagation(Cfg, AC, FactMgr, Factory); LoanPropagation.run(); DEBUG_WITH_TYPE("LifetimeLoanPropagation", LoanPropagation.dump()); + + ExpiredLoansAnalysis ExpiredAnalysis(Cfg, AC, FactMgr, Factory); } } // namespace clang ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add loan expiry analysis (PR #148712)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148712 >From 3696b6b7a6167c63d0fd5cbef607e44129feb2e2 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:32:35 + Subject: [PATCH 1/2] users/usx95/lifetime-safety-add-loan-expiry >From 3e064c102babd4abc403fa2ea4a41ce018f1352b Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:37:49 + Subject: [PATCH 2/2] [LifetimeSafety] Add loan expiry analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 61 +++ 1 file changed, 61 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index a9c0ee08950b8..8995b5a8ecc90 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -761,6 +761,65 @@ class LoanPropagationAnalysis } }; +// = // +// Expired Loans Analysis +// = // + +/// The dataflow lattice for tracking the set of expired loans. +class ExpiredLattice { +public: + LoanSet Expired; + + ExpiredLattice() : Expired(nullptr) {}; + explicit ExpiredLattice(LoanSet S) : Expired(S) {} + + bool operator==(const ExpiredLattice &Other) const { +return Expired == Other.Expired; + } + bool operator!=(const ExpiredLattice &Other) const { +return !(*this == Other); + } + + void dump(llvm::raw_ostream &OS) const { +OS << "ExpiredLattice State:\n"; +if (Expired.isEmpty()) + OS << " \n"; +for (const LoanID &LID : Expired) + OS << " Loan " << LID << " is expired\n"; + } +}; + +/// The analysis that tracks which loans have expired. +class ExpiredLoansAnalysis +: public DataflowAnalysis { + + LoanSet::Factory &Factory; + +public: + ExpiredLoansAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, + LifetimeFactory &SF) + : DataflowAnalysis(C, AC, F), Factory(SF.LoanSetFactory) {} + + using DataflowAnalysis::transfer; + + const char *getAnalysisName() const { return "ExpiredLoans"; } + + Lattice getInitialState() { return Lattice(Factory.getEmptySet()); } + + /// Merges two lattices by taking the union of the expired loan sets. + Lattice join(Lattice L1, Lattice L2) const { +return Lattice(utils::join(L1.Expired, L2.Expired, Factory)); + } + + Lattice transfer(Lattice In, const ExpireFact &F) { +return Lattice(Factory.add(In.Expired, F.getLoanID())); + } + + Lattice transfer(Lattice In, const IssueFact &F) { +return Lattice(Factory.remove(In.Expired, F.getLoanID())); + } +}; + // = // // TODO: // - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)` @@ -793,5 +852,7 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg, LoanPropagationAnalysis LoanPropagation(Cfg, AC, FactMgr, Factory); LoanPropagation.run(); DEBUG_WITH_TYPE("LifetimeLoanPropagation", LoanPropagation.dump()); + + ExpiredLoansAnalysis ExpiredAnalysis(Cfg, AC, FactMgr, Factory); } } // namespace clang ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add loan expiry analysis (PR #148712)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148712 >From 3696b6b7a6167c63d0fd5cbef607e44129feb2e2 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:32:35 + Subject: [PATCH 1/2] users/usx95/lifetime-safety-add-loan-expiry >From 3e064c102babd4abc403fa2ea4a41ce018f1352b Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:37:49 + Subject: [PATCH 2/2] [LifetimeSafety] Add loan expiry analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 61 +++ 1 file changed, 61 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index a9c0ee08950b8..8995b5a8ecc90 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -761,6 +761,65 @@ class LoanPropagationAnalysis } }; +// = // +// Expired Loans Analysis +// = // + +/// The dataflow lattice for tracking the set of expired loans. +class ExpiredLattice { +public: + LoanSet Expired; + + ExpiredLattice() : Expired(nullptr) {}; + explicit ExpiredLattice(LoanSet S) : Expired(S) {} + + bool operator==(const ExpiredLattice &Other) const { +return Expired == Other.Expired; + } + bool operator!=(const ExpiredLattice &Other) const { +return !(*this == Other); + } + + void dump(llvm::raw_ostream &OS) const { +OS << "ExpiredLattice State:\n"; +if (Expired.isEmpty()) + OS << " \n"; +for (const LoanID &LID : Expired) + OS << " Loan " << LID << " is expired\n"; + } +}; + +/// The analysis that tracks which loans have expired. +class ExpiredLoansAnalysis +: public DataflowAnalysis { + + LoanSet::Factory &Factory; + +public: + ExpiredLoansAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, + LifetimeFactory &SF) + : DataflowAnalysis(C, AC, F), Factory(SF.LoanSetFactory) {} + + using DataflowAnalysis::transfer; + + const char *getAnalysisName() const { return "ExpiredLoans"; } + + Lattice getInitialState() { return Lattice(Factory.getEmptySet()); } + + /// Merges two lattices by taking the union of the expired loan sets. + Lattice join(Lattice L1, Lattice L2) const { +return Lattice(utils::join(L1.Expired, L2.Expired, Factory)); + } + + Lattice transfer(Lattice In, const ExpireFact &F) { +return Lattice(Factory.add(In.Expired, F.getLoanID())); + } + + Lattice transfer(Lattice In, const IssueFact &F) { +return Lattice(Factory.remove(In.Expired, F.getLoanID())); + } +}; + // = // // TODO: // - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)` @@ -793,5 +852,7 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg, LoanPropagationAnalysis LoanPropagation(Cfg, AC, FactMgr, Factory); LoanPropagation.run(); DEBUG_WITH_TYPE("LifetimeLoanPropagation", LoanPropagation.dump()); + + ExpiredLoansAnalysis ExpiredAnalysis(Cfg, AC, FactMgr, Factory); } } // namespace clang ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add loan expiry analysis (PR #148712)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/148712 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add loan expiry analysis (PR #148712)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148712 >From 542bc99c1f5fb5fc28a3374f61b2fa3d059d9d75 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:32:35 + Subject: [PATCH 1/2] users/usx95/lifetime-safety-add-loan-expiry >From 6ce317303d599371fc61529eb1d3e7a1624aa8fb Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:37:49 + Subject: [PATCH 2/2] [LifetimeSafety] Add loan expiry analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 62 +++ 1 file changed, 62 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index 9d1b662e3c589..52c6b18021d7a 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -763,6 +763,65 @@ class LoanPropagationAnalysis } }; +// = // +// Expired Loans Analysis +// = // + +/// The dataflow lattice for tracking the set of expired loans. +class ExpiredLattice { +public: + LoanSet Expired; + + ExpiredLattice() : Expired(nullptr) {}; + explicit ExpiredLattice(LoanSet S) : Expired(S) {} + + bool operator==(const ExpiredLattice &Other) const { +return Expired == Other.Expired; + } + bool operator!=(const ExpiredLattice &Other) const { +return !(*this == Other); + } + + void dump(llvm::raw_ostream &OS) const { +OS << "ExpiredLattice State:\n"; +if (Expired.isEmpty()) + OS << " \n"; +for (const LoanID &LID : Expired) + OS << " Loan " << LID << " is expired\n"; + } +}; + +/// The analysis that tracks which loans have expired. +class ExpiredLoansAnalysis +: public DataflowAnalysis { + + LoanSet::Factory &Factory; + +public: + ExpiredLoansAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, + LifetimeFactory &SF) + : DataflowAnalysis(C, AC, F), Factory(SF.LoanSetFactory) {} + + using DataflowAnalysis::transfer; + + const char *getAnalysisName() const { return "ExpiredLoans"; } + + Lattice getInitialState() { return Lattice(Factory.getEmptySet()); } + + /// Merges two lattices by taking the union of the expired loan sets. + Lattice join(Lattice L1, Lattice L2) const { +return Lattice(utils::join(L1.Expired, L2.Expired, Factory)); + } + + Lattice transfer(Lattice In, const ExpireFact &F) { +return Lattice(Factory.add(In.Expired, F.getLoanID())); + } + + Lattice transfer(Lattice In, const IssueFact &F) { +return Lattice(Factory.remove(In.Expired, F.getLoanID())); + } +}; + // = // // TODO: // - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)` @@ -795,5 +854,8 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg, LoanPropagationAnalysis LoanPropagation(Cfg, AC, FactMgr, Factory); LoanPropagation.run(); DEBUG_WITH_TYPE("LifetimeLoanPropagation", LoanPropagation.dump()); + + ExpiredLoansAnalysis ExpiredLoans(Cfg, AC, FactMgr, Factory); + ExpiredLoans.run(); } } // namespace clang ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/147315 >From 5fbfcd75b60d4db3a16e183f888aba1b72d87634 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 7 Jul 2025 15:13:00 + Subject: [PATCH] [LifetimeSafety] Add script performance benchmarking --- .../Analysis/LifetimeSafety/CMakeLists.txt| 49 +++ .../test/Analysis/LifetimeSafety/benchmark.py | 307 ++ .../Analysis/LifetimeSafety/requirements.txt | 2 + clang/test/CMakeLists.txt | 2 + 4 files changed, 360 insertions(+) create mode 100644 clang/test/Analysis/LifetimeSafety/CMakeLists.txt create mode 100644 clang/test/Analysis/LifetimeSafety/benchmark.py create mode 100644 clang/test/Analysis/LifetimeSafety/requirements.txt diff --git a/clang/test/Analysis/LifetimeSafety/CMakeLists.txt b/clang/test/Analysis/LifetimeSafety/CMakeLists.txt new file mode 100644 index 0..ce37a29655668 --- /dev/null +++ b/clang/test/Analysis/LifetimeSafety/CMakeLists.txt @@ -0,0 +1,49 @@ +# = +# Lifetime Analysis Benchmarking Target +# = +# This target allows running performance benchmarks for the clang lifetime analysis +# using a Python script (with managed dependencies). + +find_package(Python3 COMPONENTS Interpreter REQUIRED) + +# Define paths for the virtual environment and requirements file. +set(LIFETIME_BENCHMARK_SCRIPT + "${CMAKE_CURRENT_SOURCE_DIR}/benchmark.py") +set(LIFETIME_BENCHMARK_VENV_DIR "${CMAKE_CURRENT_BINARY_DIR}/benchmark-venv") +set(LIFETIME_BENCHMARK_REQUIREMENTS + "${CMAKE_CURRENT_SOURCE_DIR}/requirements.txt") +set(LIFETIME_BENCHMARK_OUTPUT_DIR + "${CMAKE_CURRENT_BINARY_DIR}/benchmark_results") + + +if(EXISTS ${LIFETIME_BENCHMARK_SCRIPT} AND EXISTS ${LIFETIME_BENCHMARK_REQUIREMENTS}) + + # Set up the virtual environment and install packages + add_custom_command( +OUTPUT ${LIFETIME_BENCHMARK_VENV_DIR}/pyvenv.cfg +COMMAND ${Python3_EXECUTABLE} -m venv ${LIFETIME_BENCHMARK_VENV_DIR} +COMMAND ${LIFETIME_BENCHMARK_VENV_DIR}/bin/python -m pip install -r ${LIFETIME_BENCHMARK_REQUIREMENTS} +DEPENDS ${LIFETIME_BENCHMARK_REQUIREMENTS} +COMMENT "Creating Python virtual environment and installing dependencies for benchmark..." + ) + add_custom_target(benchmark_venv_setup +DEPENDS ${LIFETIME_BENCHMARK_VENV_DIR}/pyvenv.cfg + ) + + # Main benchmark target + add_custom_target(benchmark_lifetime_safety_analysis +COMMAND ${LIFETIME_BENCHMARK_VENV_DIR}/bin/python ${LIFETIME_BENCHMARK_SCRIPT} +--clang-binary ${LLVM_BINARY_DIR}/bin/clang +--output-dir ${LIFETIME_BENCHMARK_OUTPUT_DIR} + +DEPENDS clang benchmark_venv_setup + +# Display the output directly in the console. +USES_TERMINAL + +COMMENT "Running Lifetime Analysis performance benchmarks..." + ) + + set_target_properties(benchmark_lifetime_safety_analysis +PROPERTIES FOLDER "Clang/Benchmarks") +endif() diff --git a/clang/test/Analysis/LifetimeSafety/benchmark.py b/clang/test/Analysis/LifetimeSafety/benchmark.py new file mode 100644 index 0..9d5f36c51b9ee --- /dev/null +++ b/clang/test/Analysis/LifetimeSafety/benchmark.py @@ -0,0 +1,307 @@ +import sys +import argparse +import subprocess +import tempfile +import json +import os +from datetime import datetime +import numpy as np +from scipy.optimize import curve_fit +from scipy.stats import t + + +def generate_cpp_cycle_test(n: int) -> str: +""" +Generates a C++ code snippet with a specified number of pointers in a cycle. +Creates a while loop that rotates N pointers. +This pattern tests the convergence speed of the dataflow analysis when +reaching its fixed point. + +Example: +struct MyObj { int id; ~MyObj() {} }; + +void long_cycle_4(bool condition) { +MyObj v1{1}; +MyObj v2{1}; +MyObj v3{1}; +MyObj v4{1}; + +MyObj* p1 = &v1; +MyObj* p2 = &v2; +MyObj* p3 = &v3; +MyObj* p4 = &v4; + +while (condition) { +MyObj* temp = p1; +p1 = p2; +p2 = p3; +p3 = p4; +p4 = temp; +} +} +""" +if n <= 0: +return "// Number of variables must be positive." + +cpp_code = "struct MyObj { int id; ~MyObj() {} };\n\n" +cpp_code += f"void long_cycle_{n}(bool condition) {{\n" +for i in range(1, n + 1): +cpp_code += f" MyObj v{i}{{1}};\n" +cpp_code += "\n" +for i in range(1, n + 1): +cpp_code += f" MyObj* p{i} = &v{i};\n" + +cpp_code += "\n while (condition) {\n" +if n > 0: +cpp_code += f"MyObj* temp = p1;\n" +for i in range(1, n): +cpp_code += f"p{i} = p{i+1};\n" +cpp_code += f"
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
usx95 wrote: ### Merge activity * **Jul 14, 6:16 PM UTC**: A user started a stack merge that includes this pull request via [Graphite](https://app.graphite.dev/github/pr/llvm/llvm-project/147315). https://github.com/llvm/llvm-project/pull/147315 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add expired loans analysis (PR #148222)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148222 >From 19d033cb6aa4a84c78a9b37e25020f4e33e8976b Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 7 Jul 2025 15:13:00 + Subject: [PATCH 1/3] [LifetimeSafety] Add script performance benchmarking --- .../Analysis/LifetimeSafety/CMakeLists.txt| 49 +++ .../test/Analysis/LifetimeSafety/benchmark.py | 307 ++ .../Analysis/LifetimeSafety/requirements.txt | 2 + clang/test/CMakeLists.txt | 2 + 4 files changed, 360 insertions(+) create mode 100644 clang/test/Analysis/LifetimeSafety/CMakeLists.txt create mode 100644 clang/test/Analysis/LifetimeSafety/benchmark.py create mode 100644 clang/test/Analysis/LifetimeSafety/requirements.txt diff --git a/clang/test/Analysis/LifetimeSafety/CMakeLists.txt b/clang/test/Analysis/LifetimeSafety/CMakeLists.txt new file mode 100644 index 0..ce37a29655668 --- /dev/null +++ b/clang/test/Analysis/LifetimeSafety/CMakeLists.txt @@ -0,0 +1,49 @@ +# = +# Lifetime Analysis Benchmarking Target +# = +# This target allows running performance benchmarks for the clang lifetime analysis +# using a Python script (with managed dependencies). + +find_package(Python3 COMPONENTS Interpreter REQUIRED) + +# Define paths for the virtual environment and requirements file. +set(LIFETIME_BENCHMARK_SCRIPT + "${CMAKE_CURRENT_SOURCE_DIR}/benchmark.py") +set(LIFETIME_BENCHMARK_VENV_DIR "${CMAKE_CURRENT_BINARY_DIR}/benchmark-venv") +set(LIFETIME_BENCHMARK_REQUIREMENTS + "${CMAKE_CURRENT_SOURCE_DIR}/requirements.txt") +set(LIFETIME_BENCHMARK_OUTPUT_DIR + "${CMAKE_CURRENT_BINARY_DIR}/benchmark_results") + + +if(EXISTS ${LIFETIME_BENCHMARK_SCRIPT} AND EXISTS ${LIFETIME_BENCHMARK_REQUIREMENTS}) + + # Set up the virtual environment and install packages + add_custom_command( +OUTPUT ${LIFETIME_BENCHMARK_VENV_DIR}/pyvenv.cfg +COMMAND ${Python3_EXECUTABLE} -m venv ${LIFETIME_BENCHMARK_VENV_DIR} +COMMAND ${LIFETIME_BENCHMARK_VENV_DIR}/bin/python -m pip install -r ${LIFETIME_BENCHMARK_REQUIREMENTS} +DEPENDS ${LIFETIME_BENCHMARK_REQUIREMENTS} +COMMENT "Creating Python virtual environment and installing dependencies for benchmark..." + ) + add_custom_target(benchmark_venv_setup +DEPENDS ${LIFETIME_BENCHMARK_VENV_DIR}/pyvenv.cfg + ) + + # Main benchmark target + add_custom_target(benchmark_lifetime_safety_analysis +COMMAND ${LIFETIME_BENCHMARK_VENV_DIR}/bin/python ${LIFETIME_BENCHMARK_SCRIPT} +--clang-binary ${LLVM_BINARY_DIR}/bin/clang +--output-dir ${LIFETIME_BENCHMARK_OUTPUT_DIR} + +DEPENDS clang benchmark_venv_setup + +# Display the output directly in the console. +USES_TERMINAL + +COMMENT "Running Lifetime Analysis performance benchmarks..." + ) + + set_target_properties(benchmark_lifetime_safety_analysis +PROPERTIES FOLDER "Clang/Benchmarks") +endif() diff --git a/clang/test/Analysis/LifetimeSafety/benchmark.py b/clang/test/Analysis/LifetimeSafety/benchmark.py new file mode 100644 index 0..9d5f36c51b9ee --- /dev/null +++ b/clang/test/Analysis/LifetimeSafety/benchmark.py @@ -0,0 +1,307 @@ +import sys +import argparse +import subprocess +import tempfile +import json +import os +from datetime import datetime +import numpy as np +from scipy.optimize import curve_fit +from scipy.stats import t + + +def generate_cpp_cycle_test(n: int) -> str: +""" +Generates a C++ code snippet with a specified number of pointers in a cycle. +Creates a while loop that rotates N pointers. +This pattern tests the convergence speed of the dataflow analysis when +reaching its fixed point. + +Example: +struct MyObj { int id; ~MyObj() {} }; + +void long_cycle_4(bool condition) { +MyObj v1{1}; +MyObj v2{1}; +MyObj v3{1}; +MyObj v4{1}; + +MyObj* p1 = &v1; +MyObj* p2 = &v2; +MyObj* p3 = &v3; +MyObj* p4 = &v4; + +while (condition) { +MyObj* temp = p1; +p1 = p2; +p2 = p3; +p3 = p4; +p4 = temp; +} +} +""" +if n <= 0: +return "// Number of variables must be positive." + +cpp_code = "struct MyObj { int id; ~MyObj() {} };\n\n" +cpp_code += f"void long_cycle_{n}(bool condition) {{\n" +for i in range(1, n + 1): +cpp_code += f" MyObj v{i}{{1}};\n" +cpp_code += "\n" +for i in range(1, n + 1): +cpp_code += f" MyObj* p{i} = &v{i};\n" + +cpp_code += "\n while (condition) {\n" +if n > 0: +cpp_code += f"MyObj* temp = p1;\n" +for i in range(1, n): +cpp_code += f"p{i} = p{i+1};\n" +cpp_code +=
[llvm-branch-commits] [clang] [LifetimeSafety] Add script for performance benchmarking (PR #147315)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/147315 >From 19d033cb6aa4a84c78a9b37e25020f4e33e8976b Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 7 Jul 2025 15:13:00 + Subject: [PATCH] [LifetimeSafety] Add script performance benchmarking --- .../Analysis/LifetimeSafety/CMakeLists.txt| 49 +++ .../test/Analysis/LifetimeSafety/benchmark.py | 307 ++ .../Analysis/LifetimeSafety/requirements.txt | 2 + clang/test/CMakeLists.txt | 2 + 4 files changed, 360 insertions(+) create mode 100644 clang/test/Analysis/LifetimeSafety/CMakeLists.txt create mode 100644 clang/test/Analysis/LifetimeSafety/benchmark.py create mode 100644 clang/test/Analysis/LifetimeSafety/requirements.txt diff --git a/clang/test/Analysis/LifetimeSafety/CMakeLists.txt b/clang/test/Analysis/LifetimeSafety/CMakeLists.txt new file mode 100644 index 0..ce37a29655668 --- /dev/null +++ b/clang/test/Analysis/LifetimeSafety/CMakeLists.txt @@ -0,0 +1,49 @@ +# = +# Lifetime Analysis Benchmarking Target +# = +# This target allows running performance benchmarks for the clang lifetime analysis +# using a Python script (with managed dependencies). + +find_package(Python3 COMPONENTS Interpreter REQUIRED) + +# Define paths for the virtual environment and requirements file. +set(LIFETIME_BENCHMARK_SCRIPT + "${CMAKE_CURRENT_SOURCE_DIR}/benchmark.py") +set(LIFETIME_BENCHMARK_VENV_DIR "${CMAKE_CURRENT_BINARY_DIR}/benchmark-venv") +set(LIFETIME_BENCHMARK_REQUIREMENTS + "${CMAKE_CURRENT_SOURCE_DIR}/requirements.txt") +set(LIFETIME_BENCHMARK_OUTPUT_DIR + "${CMAKE_CURRENT_BINARY_DIR}/benchmark_results") + + +if(EXISTS ${LIFETIME_BENCHMARK_SCRIPT} AND EXISTS ${LIFETIME_BENCHMARK_REQUIREMENTS}) + + # Set up the virtual environment and install packages + add_custom_command( +OUTPUT ${LIFETIME_BENCHMARK_VENV_DIR}/pyvenv.cfg +COMMAND ${Python3_EXECUTABLE} -m venv ${LIFETIME_BENCHMARK_VENV_DIR} +COMMAND ${LIFETIME_BENCHMARK_VENV_DIR}/bin/python -m pip install -r ${LIFETIME_BENCHMARK_REQUIREMENTS} +DEPENDS ${LIFETIME_BENCHMARK_REQUIREMENTS} +COMMENT "Creating Python virtual environment and installing dependencies for benchmark..." + ) + add_custom_target(benchmark_venv_setup +DEPENDS ${LIFETIME_BENCHMARK_VENV_DIR}/pyvenv.cfg + ) + + # Main benchmark target + add_custom_target(benchmark_lifetime_safety_analysis +COMMAND ${LIFETIME_BENCHMARK_VENV_DIR}/bin/python ${LIFETIME_BENCHMARK_SCRIPT} +--clang-binary ${LLVM_BINARY_DIR}/bin/clang +--output-dir ${LIFETIME_BENCHMARK_OUTPUT_DIR} + +DEPENDS clang benchmark_venv_setup + +# Display the output directly in the console. +USES_TERMINAL + +COMMENT "Running Lifetime Analysis performance benchmarks..." + ) + + set_target_properties(benchmark_lifetime_safety_analysis +PROPERTIES FOLDER "Clang/Benchmarks") +endif() diff --git a/clang/test/Analysis/LifetimeSafety/benchmark.py b/clang/test/Analysis/LifetimeSafety/benchmark.py new file mode 100644 index 0..9d5f36c51b9ee --- /dev/null +++ b/clang/test/Analysis/LifetimeSafety/benchmark.py @@ -0,0 +1,307 @@ +import sys +import argparse +import subprocess +import tempfile +import json +import os +from datetime import datetime +import numpy as np +from scipy.optimize import curve_fit +from scipy.stats import t + + +def generate_cpp_cycle_test(n: int) -> str: +""" +Generates a C++ code snippet with a specified number of pointers in a cycle. +Creates a while loop that rotates N pointers. +This pattern tests the convergence speed of the dataflow analysis when +reaching its fixed point. + +Example: +struct MyObj { int id; ~MyObj() {} }; + +void long_cycle_4(bool condition) { +MyObj v1{1}; +MyObj v2{1}; +MyObj v3{1}; +MyObj v4{1}; + +MyObj* p1 = &v1; +MyObj* p2 = &v2; +MyObj* p3 = &v3; +MyObj* p4 = &v4; + +while (condition) { +MyObj* temp = p1; +p1 = p2; +p2 = p3; +p3 = p4; +p4 = temp; +} +} +""" +if n <= 0: +return "// Number of variables must be positive." + +cpp_code = "struct MyObj { int id; ~MyObj() {} };\n\n" +cpp_code += f"void long_cycle_{n}(bool condition) {{\n" +for i in range(1, n + 1): +cpp_code += f" MyObj v{i}{{1}};\n" +cpp_code += "\n" +for i in range(1, n + 1): +cpp_code += f" MyObj* p{i} = &v{i};\n" + +cpp_code += "\n while (condition) {\n" +if n > 0: +cpp_code += f"MyObj* temp = p1;\n" +for i in range(1, n): +cpp_code += f"p{i} = p{i+1};\n" +cpp_code += f"
[llvm-branch-commits] [clang] [LifetimeSafety] Add expired loans analysis (PR #148222)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/148222 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add expired loans analysis (PR #148222)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148222 >From eb33d75e1ad1faf621f90d0b8f6ac3deab267084 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Fri, 11 Jul 2025 11:11:47 + Subject: [PATCH 1/3] [LifetimeSafety] Add expired loans analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 140 ++ 1 file changed, 140 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index 20f3285249ac2..a6de79cffb371 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -729,6 +729,142 @@ class LifetimeDataflow { } }; +// = // +// Expired Loans Analysis +// = // + +/// The lattice for tracking expired loans. It is a set of loan IDs. +struct ExpiredLattice { + LoanSet Expired; + + ExpiredLattice() = default; + explicit ExpiredLattice(LoanSet S) : Expired(S) {} + + bool operator==(const ExpiredLattice &Other) const { +return Expired == Other.Expired; + } + bool operator!=(const ExpiredLattice &Other) const { +return !(*this == Other); + } + + /// Computes the union of two lattices. + ExpiredLattice join(const ExpiredLattice &Other, + LoanSet::Factory &Factory) const { +LoanSet JoinedSet = Expired; +for (LoanID LID : Other.Expired) + JoinedSet = Factory.add(JoinedSet, LID); +return ExpiredLattice(JoinedSet); + } + + void dump(llvm::raw_ostream &OS) const { +OS << "ExpiredLattice State:\n"; +if (Expired.isEmpty()) + OS << " \n"; +for (const LoanID &LID : Expired) + OS << " Loan " << LID << " is expired\n"; + } +}; + +/// Transfer function for the expired loans analysis. +class ExpiredLoansTransferer { + FactManager &AllFacts; + LoanSet::Factory &SetFactory; + +public: + explicit ExpiredLoansTransferer(FactManager &F, LoanSet::Factory &SF) + : AllFacts(F), SetFactory(SF) {} + + /// Computes the exit state of a block by applying all its facts sequentially + /// to a given entry state. + ExpiredLattice transferBlock(const CFGBlock *Block, +ExpiredLattice EntryState) { +ExpiredLattice BlockState = EntryState; +llvm::ArrayRef Facts = AllFacts.getFacts(Block); + +for (const Fact *F : Facts) { + BlockState = transferFact(BlockState, F); +} +return BlockState; + } + +private: + ExpiredLattice transferFact(ExpiredLattice In, const Fact *F) { +if (const auto *EF = F->getAs()) + return ExpiredLattice(SetFactory.add(In.Expired, EF->getLoanID())); + +if (const auto *IF = F->getAs()) + return ExpiredLattice(SetFactory.remove(In.Expired, IF->getLoanID())); + +return In; + } +}; + +/// Dataflow analysis driver for tracking expired loans. +class ExpiredLoansAnalysis { + const CFG &Cfg; + AnalysisDeclContext &AC; + LoanSet::Factory SetFactory; + ExpiredLoansTransferer Xfer; + + llvm::DenseMap BlockEntryStates; + llvm::DenseMap BlockExitStates; + +public: + ExpiredLoansAnalysis(const CFG &C, FactManager &FS, AnalysisDeclContext &AC) + : Cfg(C), AC(AC), Xfer(FS, SetFactory) {} + + void run() { +llvm::TimeTraceScope TimeProfile("Expired Loans Analysis"); +ForwardDataflowWorklist Worklist(Cfg, AC); +const CFGBlock *Entry = &Cfg.getEntry(); +BlockEntryStates[Entry] = ExpiredLattice(SetFactory.getEmptySet()); +Worklist.enqueueBlock(Entry); +while (const CFGBlock *B = Worklist.dequeue()) { + ExpiredLattice EntryState = getEntryState(B); + ExpiredLattice ExitState = Xfer.transferBlock(B, EntryState); + BlockExitStates[B] = ExitState; + + for (const CFGBlock *Successor : B->succs()) { +auto SuccIt = BlockEntryStates.find(Successor); +ExpiredLattice OldSuccEntryState = (SuccIt != BlockEntryStates.end()) +? SuccIt->second +: ExpiredLattice{}; +ExpiredLattice NewSuccEntryState = +OldSuccEntryState.join(ExitState, SetFactory); +if (SuccIt == BlockEntryStates.end() || +NewSuccEntryState != OldSuccEntryState) { + BlockEntryStates[Successor] = NewSuccEntryState; + Worklist.enqueueBlock(Successor); +} + } +} + } + + void dump() const { +llvm::dbgs() << "==\n"; +llvm::dbgs() << " Expired Loans Results:\n"; +llvm::dbgs() << "==\n"; +const CFGBlock &B = Cfg.getExit(); +getExitState(&B).dump(llvm::dbgs()); + } + + ExpiredLattice getEntryState(const CFGBlock *B) const { +auto It = BlockEntryStates.find(B); +if (It != BlockEntryStates.end()) { + return It->second; +} +return ExpiredLattice(SetFacto
[llvm-branch-commits] [clang] [LifetimeSafety] Add loan expiry analysis (PR #148712)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148712 >From 7c2838035392804a2cd9bda1d0751e3633d2a31f Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:32:35 + Subject: [PATCH 1/2] users/usx95/lifetime-safety-add-loan-expiry >From ed73e3b1914a25c525bbb8f06fa0112cc4eb4bd0 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:37:49 + Subject: [PATCH 2/2] [LifetimeSafety] Add loan expiry analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 62 +++ 1 file changed, 62 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index c1bd4e82f4327..1aba655a6ead1 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -746,6 +746,65 @@ class LoanPropagationAnalysis return Factory.LoanSetFact.getEmptySet(); } }; +// = // +// Expired Loans Analysis +// = // + +/// The lattice for tracking expired loans. It is a set of loan IDs. +struct ExpiredLattice { + LoanSet Expired; + + ExpiredLattice() : Expired(nullptr) {}; + explicit ExpiredLattice(LoanSet S) : Expired(S) {} + + bool operator==(const ExpiredLattice &Other) const { +return Expired == Other.Expired; + } + bool operator!=(const ExpiredLattice &Other) const { +return !(*this == Other); + } + + void dump(llvm::raw_ostream &OS) const { +OS << "ExpiredLattice State:\n"; +if (Expired.isEmpty()) + OS << " \n"; +for (const LoanID &LID : Expired) + OS << " Loan " << LID << " is expired\n"; + } +}; + +class ExpiredLoansAnalysis +: public DataflowAnalysis { + + LoanSet::Factory &SetFactory; + +public: + ExpiredLoansAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, + LoanSet::Factory &SF) + : DataflowAnalysis(C, AC, F), SetFactory(SF) {} + + using DataflowAnalysis::transfer; + + const char *getAnalysisName() const { return "ExpiredLoans"; } + + Lattice getInitialState() { return Lattice(SetFactory.getEmptySet()); } + + Lattice join(Lattice L1, Lattice L2) const { +LoanSet JoinedSet = L1.Expired; +for (LoanID LID : L2.Expired) + JoinedSet = SetFactory.add(JoinedSet, LID); +return Lattice(JoinedSet); + } + + Lattice transfer(Lattice In, const ExpireFact &F) { +return Lattice(SetFactory.add(In.Expired, F.getLoanID())); + } + + Lattice transfer(Lattice In, const IssueFact &F) { +return Lattice(SetFactory.remove(In.Expired, F.getLoanID())); + } +}; + // = // // TODO: // - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)` @@ -778,5 +837,8 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg, LoanPropagationAnalysis LoanPropagation(Cfg, AC, FactMgr, LifetimeFact); LoanPropagation.run(); DEBUG_WITH_TYPE("LifetimeLoanPropagation", LoanPropagation.dump()); + + ExpiredLoansAnalysis ExpiredAnalysis(Cfg, AC, FactMgr, + LifetimeFact.LoanSetFact); } } // namespace clang ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add loan expiry analysis (PR #148712)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148712 >From 7c2838035392804a2cd9bda1d0751e3633d2a31f Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:32:35 + Subject: [PATCH 1/2] users/usx95/lifetime-safety-add-loan-expiry >From ed73e3b1914a25c525bbb8f06fa0112cc4eb4bd0 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:37:49 + Subject: [PATCH 2/2] [LifetimeSafety] Add loan expiry analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 62 +++ 1 file changed, 62 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index c1bd4e82f4327..1aba655a6ead1 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -746,6 +746,65 @@ class LoanPropagationAnalysis return Factory.LoanSetFact.getEmptySet(); } }; +// = // +// Expired Loans Analysis +// = // + +/// The lattice for tracking expired loans. It is a set of loan IDs. +struct ExpiredLattice { + LoanSet Expired; + + ExpiredLattice() : Expired(nullptr) {}; + explicit ExpiredLattice(LoanSet S) : Expired(S) {} + + bool operator==(const ExpiredLattice &Other) const { +return Expired == Other.Expired; + } + bool operator!=(const ExpiredLattice &Other) const { +return !(*this == Other); + } + + void dump(llvm::raw_ostream &OS) const { +OS << "ExpiredLattice State:\n"; +if (Expired.isEmpty()) + OS << " \n"; +for (const LoanID &LID : Expired) + OS << " Loan " << LID << " is expired\n"; + } +}; + +class ExpiredLoansAnalysis +: public DataflowAnalysis { + + LoanSet::Factory &SetFactory; + +public: + ExpiredLoansAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, + LoanSet::Factory &SF) + : DataflowAnalysis(C, AC, F), SetFactory(SF) {} + + using DataflowAnalysis::transfer; + + const char *getAnalysisName() const { return "ExpiredLoans"; } + + Lattice getInitialState() { return Lattice(SetFactory.getEmptySet()); } + + Lattice join(Lattice L1, Lattice L2) const { +LoanSet JoinedSet = L1.Expired; +for (LoanID LID : L2.Expired) + JoinedSet = SetFactory.add(JoinedSet, LID); +return Lattice(JoinedSet); + } + + Lattice transfer(Lattice In, const ExpireFact &F) { +return Lattice(SetFactory.add(In.Expired, F.getLoanID())); + } + + Lattice transfer(Lattice In, const IssueFact &F) { +return Lattice(SetFactory.remove(In.Expired, F.getLoanID())); + } +}; + // = // // TODO: // - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)` @@ -778,5 +837,8 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg, LoanPropagationAnalysis LoanPropagation(Cfg, AC, FactMgr, LifetimeFact); LoanPropagation.run(); DEBUG_WITH_TYPE("LifetimeLoanPropagation", LoanPropagation.dump()); + + ExpiredLoansAnalysis ExpiredAnalysis(Cfg, AC, FactMgr, + LifetimeFact.LoanSetFact); } } // namespace clang ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add loan expiry analysis (PR #148712)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148712 >From a9cb32152b8ba94a6a93c7923cce1abac43c9022 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:32:35 + Subject: [PATCH 1/2] users/usx95/lifetime-safety-add-loan-expiry >From a50b00e1b5394dacd635fd1da3aef83eb54348e5 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:37:49 + Subject: [PATCH 2/2] [LifetimeSafety] Add loan expiry analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 62 +++ 1 file changed, 62 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index 99bd7bc36faf5..1ac8f42318b8d 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -747,6 +747,65 @@ class LoanPropagationAnalysis } }; +// = // +// Expired Loans Analysis +// = // + +/// The lattice for tracking expired loans. It is a set of loan IDs. +struct ExpiredLattice { + LoanSet Expired; + + ExpiredLattice() : Expired(nullptr) {}; + explicit ExpiredLattice(LoanSet S) : Expired(S) {} + + bool operator==(const ExpiredLattice &Other) const { +return Expired == Other.Expired; + } + bool operator!=(const ExpiredLattice &Other) const { +return !(*this == Other); + } + + void dump(llvm::raw_ostream &OS) const { +OS << "ExpiredLattice State:\n"; +if (Expired.isEmpty()) + OS << " \n"; +for (const LoanID &LID : Expired) + OS << " Loan " << LID << " is expired\n"; + } +}; + +class ExpiredLoansAnalysis +: public DataflowAnalysis { + + LoanSet::Factory &SetFactory; + +public: + ExpiredLoansAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, + LoanSet::Factory &SF) + : DataflowAnalysis(C, AC, F), SetFactory(SF) {} + + using DataflowAnalysis::transfer; + + const char *getAnalysisName() const { return "ExpiredLoans"; } + + Lattice getInitialState() { return Lattice(SetFactory.getEmptySet()); } + + Lattice join(Lattice L1, Lattice L2) const { +LoanSet JoinedSet = L1.Expired; +for (LoanID LID : L2.Expired) + JoinedSet = SetFactory.add(JoinedSet, LID); +return Lattice(JoinedSet); + } + + Lattice transfer(Lattice In, const ExpireFact &F) { +return Lattice(SetFactory.add(In.Expired, F.getLoanID())); + } + + Lattice transfer(Lattice In, const IssueFact &F) { +return Lattice(SetFactory.remove(In.Expired, F.getLoanID())); + } +}; + // = // // TODO: // - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)` @@ -779,5 +838,8 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg, LoanPropagationAnalysis LoanPropagation(Cfg, AC, FactMgr, LifetimeFact); LoanPropagation.run(); DEBUG_WITH_TYPE("LifetimeLoanPropagation", LoanPropagation.dump()); + + ExpiredLoansAnalysis ExpiredAnalysis(Cfg, AC, FactMgr, + LifetimeFact.LoanSetFact); } } // namespace clang ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add loan expiry analysis (PR #148712)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148712 >From a9cb32152b8ba94a6a93c7923cce1abac43c9022 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:32:35 + Subject: [PATCH 1/2] users/usx95/lifetime-safety-add-loan-expiry >From a50b00e1b5394dacd635fd1da3aef83eb54348e5 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:37:49 + Subject: [PATCH 2/2] [LifetimeSafety] Add loan expiry analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 62 +++ 1 file changed, 62 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index 99bd7bc36faf5..1ac8f42318b8d 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -747,6 +747,65 @@ class LoanPropagationAnalysis } }; +// = // +// Expired Loans Analysis +// = // + +/// The lattice for tracking expired loans. It is a set of loan IDs. +struct ExpiredLattice { + LoanSet Expired; + + ExpiredLattice() : Expired(nullptr) {}; + explicit ExpiredLattice(LoanSet S) : Expired(S) {} + + bool operator==(const ExpiredLattice &Other) const { +return Expired == Other.Expired; + } + bool operator!=(const ExpiredLattice &Other) const { +return !(*this == Other); + } + + void dump(llvm::raw_ostream &OS) const { +OS << "ExpiredLattice State:\n"; +if (Expired.isEmpty()) + OS << " \n"; +for (const LoanID &LID : Expired) + OS << " Loan " << LID << " is expired\n"; + } +}; + +class ExpiredLoansAnalysis +: public DataflowAnalysis { + + LoanSet::Factory &SetFactory; + +public: + ExpiredLoansAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, + LoanSet::Factory &SF) + : DataflowAnalysis(C, AC, F), SetFactory(SF) {} + + using DataflowAnalysis::transfer; + + const char *getAnalysisName() const { return "ExpiredLoans"; } + + Lattice getInitialState() { return Lattice(SetFactory.getEmptySet()); } + + Lattice join(Lattice L1, Lattice L2) const { +LoanSet JoinedSet = L1.Expired; +for (LoanID LID : L2.Expired) + JoinedSet = SetFactory.add(JoinedSet, LID); +return Lattice(JoinedSet); + } + + Lattice transfer(Lattice In, const ExpireFact &F) { +return Lattice(SetFactory.add(In.Expired, F.getLoanID())); + } + + Lattice transfer(Lattice In, const IssueFact &F) { +return Lattice(SetFactory.remove(In.Expired, F.getLoanID())); + } +}; + // = // // TODO: // - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)` @@ -779,5 +838,8 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg, LoanPropagationAnalysis LoanPropagation(Cfg, AC, FactMgr, LifetimeFact); LoanPropagation.run(); DEBUG_WITH_TYPE("LifetimeLoanPropagation", LoanPropagation.dump()); + + ExpiredLoansAnalysis ExpiredAnalysis(Cfg, AC, FactMgr, + LifetimeFact.LoanSetFact); } } // namespace clang ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add loan expiry analysis (PR #148712)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148712 >From 30deaddc558581426833360d74b302c1556f01ec Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:32:35 + Subject: [PATCH 1/2] users/usx95/lifetime-safety-add-loan-expiry >From 04d61938d4e1334441538405f4f0698f8f6ae74e Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:37:49 + Subject: [PATCH 2/2] [LifetimeSafety] Add loan expiry analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 61 +++ 1 file changed, 61 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index 0e013ec23e776..add652d4ce601 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -767,6 +767,64 @@ class LoanPropagationAnalysis } }; +// = // +// Expired Loans Analysis +// = // + +/// The dataflow lattice for tracking the set of expired loans. +struct ExpiredLattice { + LoanSet Expired; + + ExpiredLattice() : Expired(nullptr) {}; + explicit ExpiredLattice(LoanSet S) : Expired(S) {} + + bool operator==(const ExpiredLattice &Other) const { +return Expired == Other.Expired; + } + bool operator!=(const ExpiredLattice &Other) const { +return !(*this == Other); + } + + void dump(llvm::raw_ostream &OS) const { +OS << "ExpiredLattice State:\n"; +if (Expired.isEmpty()) + OS << " \n"; +for (const LoanID &LID : Expired) + OS << " Loan " << LID << " is expired\n"; + } +}; + +/// The analysis that tracks which loans have expired. +class ExpiredLoansAnalysis +: public DataflowAnalysis { + + LoanSet::Factory &Factory; + +public: + ExpiredLoansAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, + LifetimeFactory &SF) + : DataflowAnalysis(C, AC, F), Factory(SF.LoanSetFactory) {} + + using DataflowAnalysis::transfer; + + StringRef getAnalysisName() const { return "ExpiredLoans"; } + + Lattice getInitialState() { return Lattice(Factory.getEmptySet()); } + + /// Merges two lattices by taking the union of the expired loan sets. + Lattice join(Lattice L1, Lattice L2) const { +return Lattice(utils::join(L1.Expired, L2.Expired, Factory)); + } + + Lattice transfer(Lattice In, const ExpireFact &F) { +return Lattice(Factory.add(In.Expired, F.getLoanID())); + } + + Lattice transfer(Lattice In, const IssueFact &F) { +return Lattice(Factory.remove(In.Expired, F.getLoanID())); + } +}; + // = // // TODO: // - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)` @@ -799,5 +857,8 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg, LoanPropagationAnalysis LoanPropagation(Cfg, AC, FactMgr, Factory); LoanPropagation.run(); DEBUG_WITH_TYPE("LifetimeLoanPropagation", LoanPropagation.dump()); + + ExpiredLoansAnalysis ExpiredLoans(Cfg, AC, FactMgr, Factory); + ExpiredLoans.run(); } } // namespace clang ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add loan expiry analysis (PR #148712)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148712 >From 30deaddc558581426833360d74b302c1556f01ec Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:32:35 + Subject: [PATCH 1/2] users/usx95/lifetime-safety-add-loan-expiry >From 04d61938d4e1334441538405f4f0698f8f6ae74e Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:37:49 + Subject: [PATCH 2/2] [LifetimeSafety] Add loan expiry analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 61 +++ 1 file changed, 61 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index 0e013ec23e776..add652d4ce601 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -767,6 +767,64 @@ class LoanPropagationAnalysis } }; +// = // +// Expired Loans Analysis +// = // + +/// The dataflow lattice for tracking the set of expired loans. +struct ExpiredLattice { + LoanSet Expired; + + ExpiredLattice() : Expired(nullptr) {}; + explicit ExpiredLattice(LoanSet S) : Expired(S) {} + + bool operator==(const ExpiredLattice &Other) const { +return Expired == Other.Expired; + } + bool operator!=(const ExpiredLattice &Other) const { +return !(*this == Other); + } + + void dump(llvm::raw_ostream &OS) const { +OS << "ExpiredLattice State:\n"; +if (Expired.isEmpty()) + OS << " \n"; +for (const LoanID &LID : Expired) + OS << " Loan " << LID << " is expired\n"; + } +}; + +/// The analysis that tracks which loans have expired. +class ExpiredLoansAnalysis +: public DataflowAnalysis { + + LoanSet::Factory &Factory; + +public: + ExpiredLoansAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, + LifetimeFactory &SF) + : DataflowAnalysis(C, AC, F), Factory(SF.LoanSetFactory) {} + + using DataflowAnalysis::transfer; + + StringRef getAnalysisName() const { return "ExpiredLoans"; } + + Lattice getInitialState() { return Lattice(Factory.getEmptySet()); } + + /// Merges two lattices by taking the union of the expired loan sets. + Lattice join(Lattice L1, Lattice L2) const { +return Lattice(utils::join(L1.Expired, L2.Expired, Factory)); + } + + Lattice transfer(Lattice In, const ExpireFact &F) { +return Lattice(Factory.add(In.Expired, F.getLoanID())); + } + + Lattice transfer(Lattice In, const IssueFact &F) { +return Lattice(Factory.remove(In.Expired, F.getLoanID())); + } +}; + // = // // TODO: // - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)` @@ -799,5 +857,8 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg, LoanPropagationAnalysis LoanPropagation(Cfg, AC, FactMgr, Factory); LoanPropagation.run(); DEBUG_WITH_TYPE("LifetimeLoanPropagation", LoanPropagation.dump()); + + ExpiredLoansAnalysis ExpiredLoans(Cfg, AC, FactMgr, Factory); + ExpiredLoans.run(); } } // namespace clang ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add loan expiry analysis (PR #148712)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148712 >From 63fc65843dfd135d60bb45b1311a21d60338 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:32:35 + Subject: [PATCH 1/2] users/usx95/lifetime-safety-add-loan-expiry >From 5f0991338d17813d9af276a0cea2d30875a9aa23 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:37:49 + Subject: [PATCH 2/2] [LifetimeSafety] Add loan expiry analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 64 +++ 1 file changed, 64 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index f9a7093987896..217b02b416c1a 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -518,6 +518,8 @@ enum class Direction { Forward, Backward }; /// analysis. /// \tparam LatticeType The dataflow lattice used by the analysis. /// \tparam Dir The direction of the analysis (Forward or Backward). +/// TODO: Maybe use the dataflow framework! The framework might need changes +/// to support the current comparison done at block-entry. template class DataflowAnalysis { public: @@ -775,6 +777,65 @@ class LoanPropagationAnalysis } }; +// = // +// Expired Loans Analysis +// = // + +/// The dataflow lattice for tracking the set of expired loans. +struct ExpiredLattice { + LoanSet Expired; + + ExpiredLattice() : Expired(nullptr) {}; + explicit ExpiredLattice(LoanSet S) : Expired(S) {} + + bool operator==(const ExpiredLattice &Other) const { +return Expired == Other.Expired; + } + bool operator!=(const ExpiredLattice &Other) const { +return !(*this == Other); + } + + void dump(llvm::raw_ostream &OS) const { +OS << "ExpiredLattice State:\n"; +if (Expired.isEmpty()) + OS << " \n"; +for (const LoanID &LID : Expired) + OS << " Loan " << LID << " is expired\n"; + } +}; + +/// The analysis that tracks which loans have expired. +class ExpiredLoansAnalysis +: public DataflowAnalysis { + + LoanSet::Factory &Factory; + +public: + ExpiredLoansAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, + LifetimeFactory &SF) + : DataflowAnalysis(C, AC, F), Factory(SF.LoanSetFactory) {} + + using Base::transfer; + + StringRef getAnalysisName() const { return "ExpiredLoans"; } + + Lattice getInitialState() { return Lattice(Factory.getEmptySet()); } + + /// Merges two lattices by taking the union of the expired loan sets. + Lattice join(Lattice L1, Lattice L2) const { +return Lattice(utils::join(L1.Expired, L2.Expired, Factory)); + } + + Lattice transfer(Lattice In, const ExpireFact &F) { +return Lattice(Factory.add(In.Expired, F.getLoanID())); + } + + Lattice transfer(Lattice In, const IssueFact &F) { +return Lattice(Factory.remove(In.Expired, F.getLoanID())); + } +}; + // = // // TODO: // - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)` @@ -807,5 +868,8 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg, LoanPropagationAnalysis LoanPropagation(Cfg, AC, FactMgr, Factory); LoanPropagation.run(); DEBUG_WITH_TYPE("LifetimeLoanPropagation", LoanPropagation.dump()); + + ExpiredLoansAnalysis ExpiredLoans(Cfg, AC, FactMgr, Factory); + ExpiredLoans.run(); } } // namespace clang ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Support bidirectional dataflow analysis (PR #148967)
https://github.com/usx95 ready_for_review https://github.com/llvm/llvm-project/pull/148967 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Support bidirectional dataflow analysis (PR #148967)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/148967 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add loan expiry analysis (PR #148712)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/148712 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Support bidirectional dataflow analysis (PR #148967)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148967 >From 7502ee577452c5c5d9bb4c9a8b24d6c4825cedd1 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Tue, 15 Jul 2025 21:24:11 + Subject: [PATCH] add-backward-analysis-capability --- clang/lib/Analysis/LifetimeSafety.cpp | 108 ++ 1 file changed, 59 insertions(+), 49 deletions(-) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index 0e013ec23e776..829da3ceb4c83 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -499,13 +499,16 @@ class FactGenerator : public ConstStmtVisitor { // = // // Generic Dataflow Analysis // = // -/// A generic, policy-based driver for forward dataflow analyses. It combines + +enum class Direction { Forward, Backward }; + +/// A generic, policy-based driver for dataflow analyses. It combines /// the dataflow runner and the transferer logic into a single class hierarchy. /// /// The derived class is expected to provide: /// - A `Lattice` type. /// - `StringRef getAnalysisName() const` -/// - `Lattice getInitialState();` The initial state at the function entry. +/// - `Lattice getInitialState();` The initial state of the analysis. /// - `Lattice join(Lattice, Lattice);` Merges states from multiple CFG paths. /// - `Lattice transfer(Lattice, const FactType&);` Defines how a single /// lifetime-relevant `Fact` transforms the lattice state. Only overloads @@ -514,18 +517,23 @@ class FactGenerator : public ConstStmtVisitor { /// \tparam Derived The CRTP derived class that implements the specific /// analysis. /// \tparam LatticeType The dataflow lattice used by the analysis. +/// \tparam Dir The direction of the analysis (Forward or Backward). /// TODO: Maybe use the dataflow framework! The framework might need changes /// to support the current comparison done at block-entry. -template class DataflowAnalysis { +template +class DataflowAnalysis { public: using Lattice = LatticeType; + using Base = DataflowAnalysis; private: const CFG &Cfg; AnalysisDeclContext &AC; - llvm::DenseMap BlockEntryStates; - llvm::DenseMap BlockExitStates; + llvm::DenseMap InStates; + llvm::DenseMap OutStates; + + static constexpr bool isForward() { return Dir == Direction::Forward; } protected: FactManager &AllFacts; @@ -539,75 +547,76 @@ template class DataflowAnalysis { Derived &D = static_cast(*this); llvm::TimeTraceScope Time(D.getAnalysisName()); -ForwardDataflowWorklist Worklist(Cfg, AC); -const CFGBlock *Entry = &Cfg.getEntry(); -BlockEntryStates[Entry] = D.getInitialState(); -Worklist.enqueueBlock(Entry); -llvm::SmallBitVector Visited; -Visited.resize(Cfg.getNumBlockIDs() + 1); - -while (const CFGBlock *B = Worklist.dequeue()) { - Lattice EntryState = getEntryState(B); - Lattice ExitState = transferBlock(B, EntryState); - BlockExitStates[B] = ExitState; - Visited.set(B->getBlockID()); +using Worklist = +std::conditional_t; +Worklist W(Cfg, AC); + +const CFGBlock *Start = isForward() ? &Cfg.getEntry() : &Cfg.getExit(); +InStates[Start] = D.getInitialState(); +W.enqueueBlock(Start); - for (const CFGBlock *Successor : B->succs()) { -Lattice OldSuccEntryState = getEntryState(Successor); -Lattice NewSuccEntryState = D.join(OldSuccEntryState, ExitState); +llvm::SmallBitVector Visited(Cfg.getNumBlockIDs() + 1); -// Enqueue the successor if its entry state has changed or if we have +while (const CFGBlock *B = W.dequeue()) { + Lattice StateIn = getInState(B); + Lattice StateOut = transferBlock(B, StateIn); + OutStates[B] = StateOut; + Visited.set(B->getBlockID()); + for (const CFGBlock *AdjacentB : isForward() ? B->succs() : B->preds()) { +Lattice OldInState = getInState(AdjacentB); +Lattice NewInState = D.join(OldInState, StateOut); +// Enqueue the adjacent block if its in-state has changed or if we have // never visited it. -if (!Visited.test(Successor->getBlockID()) || -NewSuccEntryState != OldSuccEntryState) { - BlockEntryStates[Successor] = NewSuccEntryState; - Worklist.enqueueBlock(Successor); +if (!Visited.test(AdjacentB->getBlockID()) || +NewInState != OldInState) { + InStates[AdjacentB] = NewInState; + W.enqueueBlock(AdjacentB); } } } } - Lattice getEntryState(const CFGBlock *B) const { -return BlockEntryStates.lookup(B); - } + Lattice getInState(const CFGBlock *B) const { return InStates.lookup(B); } - Lattice getExitState(const CFGBlock *B) const { -return BlockExitStates.lookup(B); - }
[llvm-branch-commits] [clang] [LifetimeSafety] Add loan expiry analysis (PR #148712)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148712 >From c8089978cbc691370b2537d7942325147fd7dc3f Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:32:35 + Subject: [PATCH 1/2] users/usx95/lifetime-safety-add-loan-expiry >From aca68c29a969a33036db954f70a7d11521dbca6e Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:37:49 + Subject: [PATCH 2/2] [LifetimeSafety] Add loan expiry analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 62 +++ 1 file changed, 62 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index 829da3ceb4c83..217b02b416c1a 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -777,6 +777,65 @@ class LoanPropagationAnalysis } }; +// = // +// Expired Loans Analysis +// = // + +/// The dataflow lattice for tracking the set of expired loans. +struct ExpiredLattice { + LoanSet Expired; + + ExpiredLattice() : Expired(nullptr) {}; + explicit ExpiredLattice(LoanSet S) : Expired(S) {} + + bool operator==(const ExpiredLattice &Other) const { +return Expired == Other.Expired; + } + bool operator!=(const ExpiredLattice &Other) const { +return !(*this == Other); + } + + void dump(llvm::raw_ostream &OS) const { +OS << "ExpiredLattice State:\n"; +if (Expired.isEmpty()) + OS << " \n"; +for (const LoanID &LID : Expired) + OS << " Loan " << LID << " is expired\n"; + } +}; + +/// The analysis that tracks which loans have expired. +class ExpiredLoansAnalysis +: public DataflowAnalysis { + + LoanSet::Factory &Factory; + +public: + ExpiredLoansAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, + LifetimeFactory &SF) + : DataflowAnalysis(C, AC, F), Factory(SF.LoanSetFactory) {} + + using Base::transfer; + + StringRef getAnalysisName() const { return "ExpiredLoans"; } + + Lattice getInitialState() { return Lattice(Factory.getEmptySet()); } + + /// Merges two lattices by taking the union of the expired loan sets. + Lattice join(Lattice L1, Lattice L2) const { +return Lattice(utils::join(L1.Expired, L2.Expired, Factory)); + } + + Lattice transfer(Lattice In, const ExpireFact &F) { +return Lattice(Factory.add(In.Expired, F.getLoanID())); + } + + Lattice transfer(Lattice In, const IssueFact &F) { +return Lattice(Factory.remove(In.Expired, F.getLoanID())); + } +}; + // = // // TODO: // - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)` @@ -809,5 +868,8 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg, LoanPropagationAnalysis LoanPropagation(Cfg, AC, FactMgr, Factory); LoanPropagation.run(); DEBUG_WITH_TYPE("LifetimeLoanPropagation", LoanPropagation.dump()); + + ExpiredLoansAnalysis ExpiredLoans(Cfg, AC, FactMgr, Factory); + ExpiredLoans.run(); } } // namespace clang ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [LifetimeSafety] Add loan expiry analysis (PR #148712)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/148712 >From c8089978cbc691370b2537d7942325147fd7dc3f Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:32:35 + Subject: [PATCH 1/2] users/usx95/lifetime-safety-add-loan-expiry >From aca68c29a969a33036db954f70a7d11521dbca6e Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Mon, 14 Jul 2025 19:37:49 + Subject: [PATCH 2/2] [LifetimeSafety] Add loan expiry analysis --- clang/lib/Analysis/LifetimeSafety.cpp | 62 +++ 1 file changed, 62 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety.cpp index 829da3ceb4c83..217b02b416c1a 100644 --- a/clang/lib/Analysis/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety.cpp @@ -777,6 +777,65 @@ class LoanPropagationAnalysis } }; +// = // +// Expired Loans Analysis +// = // + +/// The dataflow lattice for tracking the set of expired loans. +struct ExpiredLattice { + LoanSet Expired; + + ExpiredLattice() : Expired(nullptr) {}; + explicit ExpiredLattice(LoanSet S) : Expired(S) {} + + bool operator==(const ExpiredLattice &Other) const { +return Expired == Other.Expired; + } + bool operator!=(const ExpiredLattice &Other) const { +return !(*this == Other); + } + + void dump(llvm::raw_ostream &OS) const { +OS << "ExpiredLattice State:\n"; +if (Expired.isEmpty()) + OS << " \n"; +for (const LoanID &LID : Expired) + OS << " Loan " << LID << " is expired\n"; + } +}; + +/// The analysis that tracks which loans have expired. +class ExpiredLoansAnalysis +: public DataflowAnalysis { + + LoanSet::Factory &Factory; + +public: + ExpiredLoansAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, + LifetimeFactory &SF) + : DataflowAnalysis(C, AC, F), Factory(SF.LoanSetFactory) {} + + using Base::transfer; + + StringRef getAnalysisName() const { return "ExpiredLoans"; } + + Lattice getInitialState() { return Lattice(Factory.getEmptySet()); } + + /// Merges two lattices by taking the union of the expired loan sets. + Lattice join(Lattice L1, Lattice L2) const { +return Lattice(utils::join(L1.Expired, L2.Expired, Factory)); + } + + Lattice transfer(Lattice In, const ExpireFact &F) { +return Lattice(Factory.add(In.Expired, F.getLoanID())); + } + + Lattice transfer(Lattice In, const IssueFact &F) { +return Lattice(Factory.remove(In.Expired, F.getLoanID())); + } +}; + // = // // TODO: // - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)` @@ -809,5 +868,8 @@ void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg, LoanPropagationAnalysis LoanPropagation(Cfg, AC, FactMgr, Factory); LoanPropagation.run(); DEBUG_WITH_TYPE("LifetimeLoanPropagation", LoanPropagation.dump()); + + ExpiredLoansAnalysis ExpiredLoans(Cfg, AC, FactMgr, Factory); + ExpiredLoans.run(); } } // namespace clang ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits