https://github.com/DEBADRIBASAK updated https://github.com/llvm/llvm-project/pull/170444
>From a7f5c0cc51ee72bfdd150eb6e4b7aa2b20e24373 Mon Sep 17 00:00:00 2001 From: Debadri Basak <[email protected]> Date: Wed, 3 Dec 2025 09:11:15 +0000 Subject: [PATCH 1/6] Adding an integer flag for setting a threhsold for skipping large CFGs and a debug-only flag for printing CFG size stats. In this context, CFG size refers to the number of facts generated by the fact generator. This is a change to effectively control bail-out strategies. --- .../Analyses/LifetimeSafety/Checker.h | 3 ++- .../Analysis/Analyses/LifetimeSafety/Facts.h | 7 +++++++ .../Analyses/LifetimeSafety/LifetimeSafety.h | 7 +++++-- clang/include/clang/Basic/LangOptions.def | 3 +++ clang/include/clang/Options/Options.td | 4 ++++ clang/lib/Analysis/LifetimeSafety/Checker.cpp | 16 ++++++++++---- clang/lib/Analysis/LifetimeSafety/Facts.cpp | 21 +++++++++++++++++++ .../LifetimeSafety/LifetimeSafety.cpp | 15 ++++++++----- clang/lib/Sema/AnalysisBasedWarnings.cpp | 2 +- 9 files changed, 65 insertions(+), 13 deletions(-) diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h index 03636be7d00c3..c609543575e0f 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h @@ -28,7 +28,8 @@ namespace clang::lifetimes::internal { void runLifetimeChecker(const LoanPropagationAnalysis &LoanPropagation, const LiveOriginsAnalysis &LiveOrigins, const FactManager &FactMgr, AnalysisDeclContext &ADC, - LifetimeSafetyReporter *Reporter); + LifetimeSafetyReporter *Reporter, + uint32_t BlockFactNumThreshold); } // namespace clang::lifetimes::internal diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h index b5f7f8746186a..5e7e93118bf10 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h @@ -218,6 +218,9 @@ class FactManager { void dump(const CFG &Cfg, AnalysisDeclContext &AC) const; + // A utility function to print the size of the CFG blocks in the analysis context. + void dumpBlockSizes(const CFG &Cfg, AnalysisDeclContext &AC) const; + /// Retrieves program points that were specially marked in the source code /// for testing. /// @@ -238,6 +241,9 @@ class FactManager { const LoanManager &getLoanMgr() const { return LoanMgr; } OriginManager &getOriginMgr() { return OriginMgr; } const OriginManager &getOriginMgr() const { return OriginMgr; } + void setBlockFactNumThreshold(uint32_t Threshold) { + BlockFactNumThreshold = Threshold; + } private: FactID NextFactID{0}; @@ -246,6 +252,7 @@ class FactManager { /// Facts for each CFG block, indexed by block ID. llvm::SmallVector<llvm::SmallVector<const Fact *>> BlockToFacts; llvm::BumpPtrAllocator FactAllocator; + uint32_t BlockFactNumThreshold = 0; }; } // namespace clang::lifetimes::internal diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h index b34a7f18b5809..29078756b3e15 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h @@ -51,7 +51,8 @@ class LifetimeSafetyReporter { /// The main entry point for the analysis. void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, - LifetimeSafetyReporter *Reporter); + LifetimeSafetyReporter *Reporter, + uint32_t BlockFactNumThreshold); namespace internal { /// An object to hold the factories for immutable collections, ensuring @@ -67,7 +68,8 @@ struct LifetimeFactory { class LifetimeSafetyAnalysis { public: LifetimeSafetyAnalysis(AnalysisDeclContext &AC, - LifetimeSafetyReporter *Reporter); + LifetimeSafetyReporter *Reporter, + uint32_t BlockFactNumThreshold); void run(); @@ -79,6 +81,7 @@ class LifetimeSafetyAnalysis { FactManager &getFactManager() { return FactMgr; } private: + uint32_t BlockFactNumThreshold; AnalysisDeclContext &AC; LifetimeSafetyReporter *Reporter; LifetimeFactory Factory; diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 40fc66ea12e34..9b6e36f0ace3a 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -501,6 +501,9 @@ LANGOPT(EnableLifetimeSafety, 1, 0, NotCompatible, "Experimental lifetime safety LANGOPT(PreserveVec3Type, 1, 0, NotCompatible, "Preserve 3-component vector type") +LANGOPT(BlockFactNumThreshold, 32, 0, NotCompatible, "Experimental CFG bailout size threshold for C++") + + #undef LANGOPT #undef ENUM_LANGOPT #undef VALUE_LANGOPT diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 756d6deed7130..7d227b3d5e194 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -5166,6 +5166,10 @@ def ffuchsia_api_level_EQ : Joined<["-"], "ffuchsia-api-level=">, Group<m_Group>, Visibility<[ClangOption, CC1Option]>, HelpText<"Set Fuchsia API level">, MarshallingInfoInt<LangOpts<"FuchsiaAPILevel">>; +def fblock_size_threshold : Joined<["-"], "fblock-size-threshold=">, + Group<m_Group>, Visibility<[ClangOption, CC1Option]>, + HelpText<"Set Threshold for block size above which lifetime analysis will be skipped">, + MarshallingInfoInt<LangOpts<"BlockFactNumThreshold">>; def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">, Visibility<[ClangOption, CC1Option, FlangOption]>, Group<m_Group>, HelpText<"Set macOS deployment target">; diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp index 1f7c282dadac2..ec5377bf8168e 100644 --- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp @@ -58,13 +58,20 @@ class LifetimeChecker { public: LifetimeChecker(const LoanPropagationAnalysis &LoanPropagation, const LiveOriginsAnalysis &LiveOrigins, const FactManager &FM, - AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter) + AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter, uint32_t BlockFactNumThreshold) : LoanPropagation(LoanPropagation), LiveOrigins(LiveOrigins), FactMgr(FM), Reporter(Reporter) { - for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>()) + if (BlockFactNumThreshold <= 0) { + llvm::errs() << "Warning: BlockFactNumThreshold should be positive.\n"; + } + for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>()) { + const auto& BlockFacts = FactMgr.getFacts(B); + if (BlockFactNumThreshold > 0 && BlockFacts.size() > BlockFactNumThreshold) + continue; for (const Fact *F : FactMgr.getFacts(B)) if (const auto *EF = F->getAs<ExpireFact>()) checkExpiry(EF); + } issuePendingWarnings(); } @@ -138,9 +145,10 @@ class LifetimeChecker { void runLifetimeChecker(const LoanPropagationAnalysis &LP, const LiveOriginsAnalysis &LO, const FactManager &FactMgr, AnalysisDeclContext &ADC, - LifetimeSafetyReporter *Reporter) { + LifetimeSafetyReporter *Reporter, + uint32_t BlockFactNumThreshold) { llvm::TimeTraceScope TimeProfile("LifetimeChecker"); - LifetimeChecker Checker(LP, LO, FactMgr, ADC, Reporter); + LifetimeChecker Checker(LP, LO, FactMgr, ADC, Reporter, BlockFactNumThreshold); } } // namespace clang::lifetimes::internal diff --git a/clang/lib/Analysis/LifetimeSafety/Facts.cpp b/clang/lib/Analysis/LifetimeSafety/Facts.cpp index 0ae7111c489e8..845c7f18df608 100644 --- a/clang/lib/Analysis/LifetimeSafety/Facts.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Facts.cpp @@ -95,6 +95,27 @@ void FactManager::dump(const CFG &Cfg, AnalysisDeclContext &AC) const { } } +void FactManager::dumpBlockSizes(const CFG &Cfg, + AnalysisDeclContext &AC) const { + llvm::dbgs() << "==========================================\n"; + llvm::dbgs() << " Lifetime Analysis CFG Block Sizes:\n"; + llvm::dbgs() << "==========================================\n"; + if (const Decl *D = AC.getDecl()) + if (const auto *ND = dyn_cast<NamedDecl>(D)) + llvm::dbgs() << "Function: " << ND->getQualifiedNameAsString() << "\n"; + // Print blocks in the order as they appear in code for a stable ordering. + for (const CFGBlock *B : *AC.getAnalysis<PostOrderCFGView>()) { + if (getFacts(B).size() > BlockFactNumThreshold) + continue; + if (B->getLabel()) { + llvm::dbgs() << " Block: " << B->getLabel()->getStmtClassName(); + } else { + llvm::dbgs() << " Block B" << B->getBlockID(); + } + llvm::dbgs() << ": Number of facts = " << getFacts(B).size() << "\n"; + } +} + llvm::ArrayRef<const Fact *> FactManager::getBlockContaining(ProgramPoint P) const { for (const auto &BlockToFactsVec : BlockToFacts) { diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp index a51ba4280f284..d057e9fa08c73 100644 --- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp @@ -32,8 +32,11 @@ namespace clang::lifetimes { namespace internal { LifetimeSafetyAnalysis::LifetimeSafetyAnalysis(AnalysisDeclContext &AC, - LifetimeSafetyReporter *Reporter) - : AC(AC), Reporter(Reporter) {} + LifetimeSafetyReporter *Reporter, + uint32_t BlockFactNumThreshold) + : BlockFactNumThreshold(BlockFactNumThreshold), AC(AC), Reporter(Reporter) { + FactMgr.setBlockFactNumThreshold(BlockFactNumThreshold); + } void LifetimeSafetyAnalysis::run() { llvm::TimeTraceScope TimeProfile("LifetimeSafetyAnalysis"); @@ -46,6 +49,7 @@ void LifetimeSafetyAnalysis::run() { FactsGenerator FactGen(FactMgr, AC); FactGen.run(); DEBUG_WITH_TYPE("LifetimeFacts", FactMgr.dump(Cfg, AC)); + DEBUG_WITH_TYPE("LifetimeCFGSizes", FactMgr.dumpBlockSizes(Cfg, AC)); /// TODO(opt): Consider optimizing individual blocks before running the /// dataflow analysis. @@ -66,13 +70,14 @@ void LifetimeSafetyAnalysis::run() { DEBUG_WITH_TYPE("LiveOrigins", LiveOrigins->dump(llvm::dbgs(), FactMgr.getTestPoints())); - runLifetimeChecker(*LoanPropagation, *LiveOrigins, FactMgr, AC, Reporter); + runLifetimeChecker(*LoanPropagation, *LiveOrigins, FactMgr, AC, Reporter, BlockFactNumThreshold); } } // namespace internal void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, - LifetimeSafetyReporter *Reporter) { - internal::LifetimeSafetyAnalysis Analysis(AC, Reporter); + LifetimeSafetyReporter *Reporter, + uint32_t BlockFactNumThreshold) { + internal::LifetimeSafetyAnalysis Analysis(AC, Reporter, BlockFactNumThreshold); Analysis.run(); } } // namespace clang::lifetimes diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 43d2b9a829545..b379279115784 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -3107,7 +3107,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) { if (AC.getCFG()) { lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S); - lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetyReporter); + lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetyReporter, S.getLangOpts().BlockFactNumThreshold); } } // Check for violations of "called once" parameter properties. >From 1f989f9103e73c439d3c63e1e74d7797a7339a0b Mon Sep 17 00:00:00 2001 From: Debadri Basak <[email protected]> Date: Wed, 3 Dec 2025 09:13:39 +0000 Subject: [PATCH 2/6] Formatting changes --- .../Analysis/Analyses/LifetimeSafety/Checker.h | 2 +- .../clang/Analysis/Analyses/LifetimeSafety/Facts.h | 3 ++- .../Analyses/LifetimeSafety/LifetimeSafety.h | 4 ++-- clang/include/clang/Options/Options.td | 11 +++++++---- clang/lib/Analysis/LifetimeSafety/Checker.cpp | 13 ++++++++----- .../lib/Analysis/LifetimeSafety/LifetimeSafety.cpp | 12 +++++++----- clang/lib/Sema/AnalysisBasedWarnings.cpp | 3 ++- 7 files changed, 29 insertions(+), 19 deletions(-) diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h index c609543575e0f..be10f298ab2ff 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h @@ -29,7 +29,7 @@ void runLifetimeChecker(const LoanPropagationAnalysis &LoanPropagation, const LiveOriginsAnalysis &LiveOrigins, const FactManager &FactMgr, AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter, - uint32_t BlockFactNumThreshold); + uint32_t BlockFactNumThreshold); } // namespace clang::lifetimes::internal diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h index 5e7e93118bf10..c6680d234ddba 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h @@ -218,7 +218,8 @@ class FactManager { void dump(const CFG &Cfg, AnalysisDeclContext &AC) const; - // A utility function to print the size of the CFG blocks in the analysis context. + // A utility function to print the size of the CFG blocks in the analysis + // context. void dumpBlockSizes(const CFG &Cfg, AnalysisDeclContext &AC) const; /// Retrieves program points that were specially marked in the source code diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h index 29078756b3e15..95b0ed71af3e0 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h @@ -52,7 +52,7 @@ class LifetimeSafetyReporter { /// The main entry point for the analysis. void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter, - uint32_t BlockFactNumThreshold); + uint32_t BlockFactNumThreshold); namespace internal { /// An object to hold the factories for immutable collections, ensuring @@ -69,7 +69,7 @@ class LifetimeSafetyAnalysis { public: LifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter, - uint32_t BlockFactNumThreshold); + uint32_t BlockFactNumThreshold); void run(); diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 7d227b3d5e194..dd367e4555228 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -5166,10 +5166,13 @@ def ffuchsia_api_level_EQ : Joined<["-"], "ffuchsia-api-level=">, Group<m_Group>, Visibility<[ClangOption, CC1Option]>, HelpText<"Set Fuchsia API level">, MarshallingInfoInt<LangOpts<"FuchsiaAPILevel">>; -def fblock_size_threshold : Joined<["-"], "fblock-size-threshold=">, - Group<m_Group>, Visibility<[ClangOption, CC1Option]>, - HelpText<"Set Threshold for block size above which lifetime analysis will be skipped">, - MarshallingInfoInt<LangOpts<"BlockFactNumThreshold">>; +def fblock_size_threshold + : Joined<["-"], "fblock-size-threshold=">, + Group<m_Group>, + Visibility<[ClangOption, CC1Option]>, + HelpText<"Set Threshold for block size above which lifetime analysis " + "will be skipped">, + MarshallingInfoInt<LangOpts<"BlockFactNumThreshold">>; def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">, Visibility<[ClangOption, CC1Option, FlangOption]>, Group<m_Group>, HelpText<"Set macOS deployment target">; diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp index ec5377bf8168e..89415d1f0bf02 100644 --- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp @@ -58,15 +58,17 @@ class LifetimeChecker { public: LifetimeChecker(const LoanPropagationAnalysis &LoanPropagation, const LiveOriginsAnalysis &LiveOrigins, const FactManager &FM, - AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter, uint32_t BlockFactNumThreshold) + AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter, + uint32_t BlockFactNumThreshold) : LoanPropagation(LoanPropagation), LiveOrigins(LiveOrigins), FactMgr(FM), Reporter(Reporter) { if (BlockFactNumThreshold <= 0) { llvm::errs() << "Warning: BlockFactNumThreshold should be positive.\n"; } for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>()) { - const auto& BlockFacts = FactMgr.getFacts(B); - if (BlockFactNumThreshold > 0 && BlockFacts.size() > BlockFactNumThreshold) + const auto &BlockFacts = FactMgr.getFacts(B); + if (BlockFactNumThreshold > 0 && + BlockFacts.size() > BlockFactNumThreshold) continue; for (const Fact *F : FactMgr.getFacts(B)) if (const auto *EF = F->getAs<ExpireFact>()) @@ -146,9 +148,10 @@ void runLifetimeChecker(const LoanPropagationAnalysis &LP, const LiveOriginsAnalysis &LO, const FactManager &FactMgr, AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter, - uint32_t BlockFactNumThreshold) { + uint32_t BlockFactNumThreshold) { llvm::TimeTraceScope TimeProfile("LifetimeChecker"); - LifetimeChecker Checker(LP, LO, FactMgr, ADC, Reporter, BlockFactNumThreshold); + LifetimeChecker Checker(LP, LO, FactMgr, ADC, Reporter, + BlockFactNumThreshold); } } // namespace clang::lifetimes::internal diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp index d057e9fa08c73..36f48ae83dfc8 100644 --- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp @@ -33,10 +33,10 @@ namespace internal { LifetimeSafetyAnalysis::LifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter, - uint32_t BlockFactNumThreshold) + uint32_t BlockFactNumThreshold) : BlockFactNumThreshold(BlockFactNumThreshold), AC(AC), Reporter(Reporter) { FactMgr.setBlockFactNumThreshold(BlockFactNumThreshold); - } +} void LifetimeSafetyAnalysis::run() { llvm::TimeTraceScope TimeProfile("LifetimeSafetyAnalysis"); @@ -70,14 +70,16 @@ void LifetimeSafetyAnalysis::run() { DEBUG_WITH_TYPE("LiveOrigins", LiveOrigins->dump(llvm::dbgs(), FactMgr.getTestPoints())); - runLifetimeChecker(*LoanPropagation, *LiveOrigins, FactMgr, AC, Reporter, BlockFactNumThreshold); + runLifetimeChecker(*LoanPropagation, *LiveOrigins, FactMgr, AC, Reporter, + BlockFactNumThreshold); } } // namespace internal void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter, - uint32_t BlockFactNumThreshold) { - internal::LifetimeSafetyAnalysis Analysis(AC, Reporter, BlockFactNumThreshold); + uint32_t BlockFactNumThreshold) { + internal::LifetimeSafetyAnalysis Analysis(AC, Reporter, + BlockFactNumThreshold); Analysis.run(); } } // namespace clang::lifetimes diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index b379279115784..c32e3c007e13c 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -3107,7 +3107,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) { if (AC.getCFG()) { lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S); - lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetyReporter, S.getLangOpts().BlockFactNumThreshold); + lifetimes::runLifetimeSafetyAnalysis( + AC, &LifetimeSafetyReporter, S.getLangOpts().BlockFactNumThreshold); } } // Check for violations of "called once" parameter properties. >From 8294f3f7b95a01f230aa754af7c6703c4cb36177 Mon Sep 17 00:00:00 2001 From: Debadri Basak <[email protected]> Date: Wed, 3 Dec 2025 09:28:23 +0000 Subject: [PATCH 3/6] Correcting the implementation of block size printing function --- clang/lib/Analysis/LifetimeSafety/Checker.cpp | 3 --- clang/lib/Analysis/LifetimeSafety/Facts.cpp | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp index 89415d1f0bf02..6622600b1ec30 100644 --- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp @@ -62,9 +62,6 @@ class LifetimeChecker { uint32_t BlockFactNumThreshold) : LoanPropagation(LoanPropagation), LiveOrigins(LiveOrigins), FactMgr(FM), Reporter(Reporter) { - if (BlockFactNumThreshold <= 0) { - llvm::errs() << "Warning: BlockFactNumThreshold should be positive.\n"; - } for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>()) { const auto &BlockFacts = FactMgr.getFacts(B); if (BlockFactNumThreshold > 0 && diff --git a/clang/lib/Analysis/LifetimeSafety/Facts.cpp b/clang/lib/Analysis/LifetimeSafety/Facts.cpp index 845c7f18df608..98f6de28154d2 100644 --- a/clang/lib/Analysis/LifetimeSafety/Facts.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Facts.cpp @@ -105,7 +105,7 @@ void FactManager::dumpBlockSizes(const CFG &Cfg, llvm::dbgs() << "Function: " << ND->getQualifiedNameAsString() << "\n"; // Print blocks in the order as they appear in code for a stable ordering. for (const CFGBlock *B : *AC.getAnalysis<PostOrderCFGView>()) { - if (getFacts(B).size() > BlockFactNumThreshold) + if (BlockFactNumThreshold > 0 && getFacts(B).size() > BlockFactNumThreshold) continue; if (B->getLabel()) { llvm::dbgs() << " Block: " << B->getLabel()->getStmtClassName(); >From 5f0dff2dbf1d4345dab8121406f99e58d250b20c Mon Sep 17 00:00:00 2001 From: Debadri Basak <[email protected]> Date: Mon, 8 Dec 2025 04:06:29 +0000 Subject: [PATCH 4/6] Adding two flags for origin count based and block count based bail-out --- .../Analyses/LifetimeSafety/LifetimeSafety.h | 12 ++++-- clang/include/clang/Basic/LangOptions.def | 2 +- clang/include/clang/Options/Options.td | 17 +++++--- clang/lib/Analysis/LifetimeSafety/Checker.cpp | 13 ++---- .../LifetimeSafety/LifetimeSafety.cpp | 42 +++++++++++++++---- clang/lib/Sema/AnalysisBasedWarnings.cpp | 2 +- .../unittests/Analysis/LifetimeSafetyTest.cpp | 2 +- 7 files changed, 62 insertions(+), 28 deletions(-) diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h index 95b0ed71af3e0..6b5b71686a758 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h @@ -24,6 +24,7 @@ #include "clang/Analysis/Analyses/LifetimeSafety/LiveOrigins.h" #include "clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h" #include "clang/Analysis/AnalysisDeclContext.h" +#include <cstdint> namespace clang::lifetimes { @@ -52,7 +53,8 @@ class LifetimeSafetyReporter { /// The main entry point for the analysis. void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter, - uint32_t BlockFactNumThreshold); + uint32_t CfgBlocknumThreshold, + uint32_t CfgOriginCountThreshold); namespace internal { /// An object to hold the factories for immutable collections, ensuring @@ -69,7 +71,8 @@ class LifetimeSafetyAnalysis { public: LifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter, - uint32_t BlockFactNumThreshold); + uint32_t CfgBlocknumThreshold, + uint32_t CfgOriginCountThreshold); void run(); @@ -81,7 +84,10 @@ class LifetimeSafetyAnalysis { FactManager &getFactManager() { return FactMgr; } private: - uint32_t BlockFactNumThreshold; + bool shouldBailOutCFGPreFactGeneration(const CFG& Cfg) const; + bool shouldBailOutCFGPostFactGeneration(const CFG& Cfg) const; + uint32_t CfgBlocknumThreshold; + uint32_t CfgOriginCountThreshold; AnalysisDeclContext &AC; LifetimeSafetyReporter *Reporter; LifetimeFactory Factory; diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 9b6e36f0ace3a..05830caea2830 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -501,7 +501,7 @@ LANGOPT(EnableLifetimeSafety, 1, 0, NotCompatible, "Experimental lifetime safety LANGOPT(PreserveVec3Type, 1, 0, NotCompatible, "Preserve 3-component vector type") -LANGOPT(BlockFactNumThreshold, 32, 0, NotCompatible, "Experimental CFG bailout size threshold for C++") +LANGOPT(CfgBlocknumThreshold, 32, 0, NotCompatible, "Experimental CFG bailout size threshold for C++") #undef LANGOPT diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index dd367e4555228..abe984b440e77 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -5166,13 +5166,20 @@ def ffuchsia_api_level_EQ : Joined<["-"], "ffuchsia-api-level=">, Group<m_Group>, Visibility<[ClangOption, CC1Option]>, HelpText<"Set Fuchsia API level">, MarshallingInfoInt<LangOpts<"FuchsiaAPILevel">>; -def fblock_size_threshold - : Joined<["-"], "fblock-size-threshold=">, +def fcfg_block_num_threshold + : Joined<["-"], "fcfg-block-num-threshold=">, Group<m_Group>, Visibility<[ClangOption, CC1Option]>, - HelpText<"Set Threshold for block size above which lifetime analysis " - "will be skipped">, - MarshallingInfoInt<LangOpts<"BlockFactNumThreshold">>; + HelpText<"Set Threshold for number of blocks above which lifetime analysis " + "will be skipped for a CFG">, + MarshallingInfoInt<LangOpts<"CfgBlocknumThreshold">>; +def fcfg_origin_count_threshold + : Joined<["-"], "fcfg-origin-count-threshold=">, + Group<m_Group>, + Visibility<[ClangOption, CC1Option]>, + HelpText<"Set Threshold for number of origins after fact generation after which lifetime analysis " + "will be skipped for a CFG">, + MarshallingInfoInt<LangOpts<"CfgOriginCountThreshold">>; def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">, Visibility<[ClangOption, CC1Option, FlangOption]>, Group<m_Group>, HelpText<"Set macOS deployment target">; diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp index 6622600b1ec30..0ced00f5fadda 100644 --- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp @@ -58,15 +58,10 @@ class LifetimeChecker { public: LifetimeChecker(const LoanPropagationAnalysis &LoanPropagation, const LiveOriginsAnalysis &LiveOrigins, const FactManager &FM, - AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter, - uint32_t BlockFactNumThreshold) + AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter) : LoanPropagation(LoanPropagation), LiveOrigins(LiveOrigins), FactMgr(FM), Reporter(Reporter) { for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>()) { - const auto &BlockFacts = FactMgr.getFacts(B); - if (BlockFactNumThreshold > 0 && - BlockFacts.size() > BlockFactNumThreshold) - continue; for (const Fact *F : FactMgr.getFacts(B)) if (const auto *EF = F->getAs<ExpireFact>()) checkExpiry(EF); @@ -144,11 +139,9 @@ class LifetimeChecker { void runLifetimeChecker(const LoanPropagationAnalysis &LP, const LiveOriginsAnalysis &LO, const FactManager &FactMgr, AnalysisDeclContext &ADC, - LifetimeSafetyReporter *Reporter, - uint32_t BlockFactNumThreshold) { + LifetimeSafetyReporter *Reporter) { llvm::TimeTraceScope TimeProfile("LifetimeChecker"); - LifetimeChecker Checker(LP, LO, FactMgr, ADC, Reporter, - BlockFactNumThreshold); + LifetimeChecker Checker(LP, LO, FactMgr, ADC, Reporter); } } // namespace clang::lifetimes::internal diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp index 36f48ae83dfc8..0865d54261ce7 100644 --- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp @@ -33,21 +33,48 @@ namespace internal { LifetimeSafetyAnalysis::LifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter, - uint32_t BlockFactNumThreshold) - : BlockFactNumThreshold(BlockFactNumThreshold), AC(AC), Reporter(Reporter) { - FactMgr.setBlockFactNumThreshold(BlockFactNumThreshold); + uint32_t CfgBlocknumThreshold, + uint32_t CfgOriginCountThreshold) + : CfgBlocknumThreshold(CfgBlocknumThreshold), CfgOriginCountThreshold(CfgOriginCountThreshold), AC(AC), Reporter(Reporter) { + FactMgr.setBlockFactNumThreshold(CfgBlocknumThreshold); +} + +bool LifetimeSafetyAnalysis::shouldBailOutCFGPreFactGeneration(const CFG& Cfg) const { + if (Cfg.getNumBlockIDs() > CfgBlocknumThreshold) { + LLVM_DEBUG(llvm::dbgs() + << "Lifetime Safety Analysis aborted: CFG too large before fact generation (" + << Cfg.getNumBlockIDs() << " blocks).\n"); + return true; + } + return false; +} + +bool LifetimeSafetyAnalysis::shouldBailOutCFGPostFactGeneration(const CFG& Cfg) const { + if (FactMgr.getOriginMgr().getNumOrigins() > CfgOriginCountThreshold) { + LLVM_DEBUG(llvm::dbgs() + << "Lifetime Safety Analysis aborted: Too many origins after fact generation (" + << FactMgr.getOriginMgr().getNumOrigins() << " origins).\n"); + return true; + } + return false; } void LifetimeSafetyAnalysis::run() { llvm::TimeTraceScope TimeProfile("LifetimeSafetyAnalysis"); const CFG &Cfg = *AC.getCFG(); + if (shouldBailOutCFGPreFactGeneration(Cfg)) { + return; + } DEBUG_WITH_TYPE("PrintCFG", Cfg.dump(AC.getASTContext().getLangOpts(), /*ShowColors=*/true)); FactMgr.init(Cfg); FactsGenerator FactGen(FactMgr, AC); FactGen.run(); + if (shouldBailOutCFGPostFactGeneration(Cfg)) { + return; + } DEBUG_WITH_TYPE("LifetimeFacts", FactMgr.dump(Cfg, AC)); DEBUG_WITH_TYPE("LifetimeCFGSizes", FactMgr.dumpBlockSizes(Cfg, AC)); @@ -70,16 +97,17 @@ void LifetimeSafetyAnalysis::run() { DEBUG_WITH_TYPE("LiveOrigins", LiveOrigins->dump(llvm::dbgs(), FactMgr.getTestPoints())); - runLifetimeChecker(*LoanPropagation, *LiveOrigins, FactMgr, AC, Reporter, - BlockFactNumThreshold); + runLifetimeChecker(*LoanPropagation, *LiveOrigins, FactMgr, AC, Reporter); } } // namespace internal void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter, - uint32_t BlockFactNumThreshold) { + uint32_t CfgBlocknumThreshold, + uint32_t CfgOriginCountThreshold) { internal::LifetimeSafetyAnalysis Analysis(AC, Reporter, - BlockFactNumThreshold); + CfgBlocknumThreshold, + CfgOriginCountThreshold); Analysis.run(); } } // namespace clang::lifetimes diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index c32e3c007e13c..ba396191bfa5f 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -3108,7 +3108,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( if (AC.getCFG()) { lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S); lifetimes::runLifetimeSafetyAnalysis( - AC, &LifetimeSafetyReporter, S.getLangOpts().BlockFactNumThreshold); + AC, &LifetimeSafetyReporter, S.getLangOpts().CfgBlocknumThreshold, S.getLangOpts().CfgOriginCountThreshold); } } // Check for violations of "called once" parameter properties. diff --git a/clang/unittests/Analysis/LifetimeSafetyTest.cpp b/clang/unittests/Analysis/LifetimeSafetyTest.cpp index a895475013c98..157b77841f533 100644 --- a/clang/unittests/Analysis/LifetimeSafetyTest.cpp +++ b/clang/unittests/Analysis/LifetimeSafetyTest.cpp @@ -62,7 +62,7 @@ class LifetimeTestRunner { BuildOptions.AddLifetime = true; // Run the main analysis. - Analysis = std::make_unique<LifetimeSafetyAnalysis>(*AnalysisCtx, nullptr); + Analysis = std::make_unique<LifetimeSafetyAnalysis>(*AnalysisCtx, nullptr, 0, 0); Analysis->run(); AnnotationToPointMap = Analysis->getFactManager().getTestPoints(); >From 58db8bfca9fe6c8371b143d90f397be247e129a4 Mon Sep 17 00:00:00 2001 From: Debadri Basak <[email protected]> Date: Thu, 11 Dec 2025 07:14:43 +0000 Subject: [PATCH 5/6] Adding block number based bailout logic --- .../Analyses/LifetimeSafety/Checker.h | 3 +- .../Analysis/Analyses/LifetimeSafety/Facts.h | 6 +-- .../Analyses/LifetimeSafety/LifetimeSafety.h | 10 ++--- clang/include/clang/Options/Options.td | 12 ++---- clang/lib/Analysis/LifetimeSafety/Facts.cpp | 15 +++++--- .../LifetimeSafety/LifetimeSafety.cpp | 38 +++++++------------ clang/lib/Sema/AnalysisBasedWarnings.cpp | 2 +- .../unittests/Analysis/LifetimeSafetyTest.cpp | 3 +- 8 files changed, 35 insertions(+), 54 deletions(-) diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h index be10f298ab2ff..03636be7d00c3 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h @@ -28,8 +28,7 @@ namespace clang::lifetimes::internal { void runLifetimeChecker(const LoanPropagationAnalysis &LoanPropagation, const LiveOriginsAnalysis &LiveOrigins, const FactManager &FactMgr, AnalysisDeclContext &ADC, - LifetimeSafetyReporter *Reporter, - uint32_t BlockFactNumThreshold); + LifetimeSafetyReporter *Reporter); } // namespace clang::lifetimes::internal diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h index c6680d234ddba..b10b0a95a82fa 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h @@ -242,8 +242,8 @@ class FactManager { const LoanManager &getLoanMgr() const { return LoanMgr; } OriginManager &getOriginMgr() { return OriginMgr; } const OriginManager &getOriginMgr() const { return OriginMgr; } - void setBlockFactNumThreshold(uint32_t Threshold) { - BlockFactNumThreshold = Threshold; + void setBlockNumThreshold(uint32_t Threshold) { + BlockNumThreshold = Threshold; } private: @@ -253,7 +253,7 @@ class FactManager { /// Facts for each CFG block, indexed by block ID. llvm::SmallVector<llvm::SmallVector<const Fact *>> BlockToFacts; llvm::BumpPtrAllocator FactAllocator; - uint32_t BlockFactNumThreshold = 0; + uint32_t BlockNumThreshold = 0; }; } // namespace clang::lifetimes::internal diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h index 6b5b71686a758..e32e91befca8f 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h @@ -53,8 +53,7 @@ class LifetimeSafetyReporter { /// The main entry point for the analysis. void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter, - uint32_t CfgBlocknumThreshold, - uint32_t CfgOriginCountThreshold); + uint32_t CfgBlocknumThreshold); namespace internal { /// An object to hold the factories for immutable collections, ensuring @@ -71,8 +70,7 @@ class LifetimeSafetyAnalysis { public: LifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter, - uint32_t CfgBlocknumThreshold, - uint32_t CfgOriginCountThreshold); + uint32_t CfgBlocknumThreshold); void run(); @@ -84,10 +82,8 @@ class LifetimeSafetyAnalysis { FactManager &getFactManager() { return FactMgr; } private: - bool shouldBailOutCFGPreFactGeneration(const CFG& Cfg) const; - bool shouldBailOutCFGPostFactGeneration(const CFG& Cfg) const; + bool shouldBailOutCFGPreFactGeneration(const CFG &Cfg) const; uint32_t CfgBlocknumThreshold; - uint32_t CfgOriginCountThreshold; AnalysisDeclContext &AC; LifetimeSafetyReporter *Reporter; LifetimeFactory Factory; diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index abe984b440e77..975d7bf0341a9 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -5170,16 +5170,10 @@ def fcfg_block_num_threshold : Joined<["-"], "fcfg-block-num-threshold=">, Group<m_Group>, Visibility<[ClangOption, CC1Option]>, - HelpText<"Set Threshold for number of blocks above which lifetime analysis " - "will be skipped for a CFG">, + HelpText< + "Set Threshold for number of blocks above which lifetime analysis " + "will be skipped for a CFG">, MarshallingInfoInt<LangOpts<"CfgBlocknumThreshold">>; -def fcfg_origin_count_threshold - : Joined<["-"], "fcfg-origin-count-threshold=">, - Group<m_Group>, - Visibility<[ClangOption, CC1Option]>, - HelpText<"Set Threshold for number of origins after fact generation after which lifetime analysis " - "will be skipped for a CFG">, - MarshallingInfoInt<LangOpts<"CfgOriginCountThreshold">>; def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">, Visibility<[ClangOption, CC1Option, FlangOption]>, Group<m_Group>, HelpText<"Set macOS deployment target">; diff --git a/clang/lib/Analysis/LifetimeSafety/Facts.cpp b/clang/lib/Analysis/LifetimeSafety/Facts.cpp index 98f6de28154d2..9cdde1b4d77d9 100644 --- a/clang/lib/Analysis/LifetimeSafety/Facts.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Facts.cpp @@ -103,16 +103,19 @@ void FactManager::dumpBlockSizes(const CFG &Cfg, if (const Decl *D = AC.getDecl()) if (const auto *ND = dyn_cast<NamedDecl>(D)) llvm::dbgs() << "Function: " << ND->getQualifiedNameAsString() << "\n"; + llvm::dbgs() << "Number of CFG Blocks: " << Cfg.getNumBlockIDs() << "\n"; + if (BlockNumThreshold > 0 && Cfg.getNumBlockIDs() > BlockNumThreshold) { + llvm::dbgs() << "CFG Block Number Threshold: " << BlockNumThreshold << "\n"; + llvm::dbgs() << "Bailed out before generating facts.\n"; + return; + } // Print blocks in the order as they appear in code for a stable ordering. for (const CFGBlock *B : *AC.getAnalysis<PostOrderCFGView>()) { - if (BlockFactNumThreshold > 0 && getFacts(B).size() > BlockFactNumThreshold) - continue; - if (B->getLabel()) { + if (B->getLabel()) llvm::dbgs() << " Block: " << B->getLabel()->getStmtClassName(); - } else { + else llvm::dbgs() << " Block B" << B->getBlockID(); - } - llvm::dbgs() << ": Number of facts = " << getFacts(B).size() << "\n"; + llvm::dbgs() << ": Number of elements = " << B->size() << "\n"; } } diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp index 0865d54261ce7..af3b3cc87f872 100644 --- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp @@ -28,32 +28,26 @@ #include "llvm/Support/TimeProfiler.h" #include <memory> +#undef DEBUG_TYPE +#define DEBUG_TYPE "lifetime-safety" + namespace clang::lifetimes { namespace internal { LifetimeSafetyAnalysis::LifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter, - uint32_t CfgBlocknumThreshold, - uint32_t CfgOriginCountThreshold) - : CfgBlocknumThreshold(CfgBlocknumThreshold), CfgOriginCountThreshold(CfgOriginCountThreshold), AC(AC), Reporter(Reporter) { - FactMgr.setBlockFactNumThreshold(CfgBlocknumThreshold); + uint32_t CfgBlocknumThreshold) + : CfgBlocknumThreshold(CfgBlocknumThreshold), AC(AC), Reporter(Reporter) { + FactMgr.setBlockNumThreshold(CfgBlocknumThreshold); } bool LifetimeSafetyAnalysis::shouldBailOutCFGPreFactGeneration(const CFG& Cfg) const { - if (Cfg.getNumBlockIDs() > CfgBlocknumThreshold) { + if ((CfgBlocknumThreshold > 0) && + (Cfg.getNumBlockIDs() > CfgBlocknumThreshold)) { LLVM_DEBUG(llvm::dbgs() - << "Lifetime Safety Analysis aborted: CFG too large before fact generation (" - << Cfg.getNumBlockIDs() << " blocks).\n"); - return true; - } - return false; -} - -bool LifetimeSafetyAnalysis::shouldBailOutCFGPostFactGeneration(const CFG& Cfg) const { - if (FactMgr.getOriginMgr().getNumOrigins() > CfgOriginCountThreshold) { - LLVM_DEBUG(llvm::dbgs() - << "Lifetime Safety Analysis aborted: Too many origins after fact generation (" - << FactMgr.getOriginMgr().getNumOrigins() << " origins).\n"); + << "Aborting Lifetime Safety analysis for current CFG as it has " + "blocks exceeding the thresold. Number of blocks: " + << Cfg.getNumBlockIDs() << "\n"); return true; } return false; @@ -72,9 +66,6 @@ void LifetimeSafetyAnalysis::run() { FactsGenerator FactGen(FactMgr, AC); FactGen.run(); - if (shouldBailOutCFGPostFactGeneration(Cfg)) { - return; - } DEBUG_WITH_TYPE("LifetimeFacts", FactMgr.dump(Cfg, AC)); DEBUG_WITH_TYPE("LifetimeCFGSizes", FactMgr.dumpBlockSizes(Cfg, AC)); @@ -103,11 +94,8 @@ void LifetimeSafetyAnalysis::run() { void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter, - uint32_t CfgBlocknumThreshold, - uint32_t CfgOriginCountThreshold) { - internal::LifetimeSafetyAnalysis Analysis(AC, Reporter, - CfgBlocknumThreshold, - CfgOriginCountThreshold); + uint32_t CfgBlocknumThreshold) { + internal::LifetimeSafetyAnalysis Analysis(AC, Reporter, CfgBlocknumThreshold); Analysis.run(); } } // namespace clang::lifetimes diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index ba396191bfa5f..00d8e52bcbbea 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -3108,7 +3108,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( if (AC.getCFG()) { lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S); lifetimes::runLifetimeSafetyAnalysis( - AC, &LifetimeSafetyReporter, S.getLangOpts().CfgBlocknumThreshold, S.getLangOpts().CfgOriginCountThreshold); + AC, &LifetimeSafetyReporter, S.getLangOpts().CfgBlocknumThreshold); } } // Check for violations of "called once" parameter properties. diff --git a/clang/unittests/Analysis/LifetimeSafetyTest.cpp b/clang/unittests/Analysis/LifetimeSafetyTest.cpp index 157b77841f533..1f27df26d30f6 100644 --- a/clang/unittests/Analysis/LifetimeSafetyTest.cpp +++ b/clang/unittests/Analysis/LifetimeSafetyTest.cpp @@ -62,7 +62,8 @@ class LifetimeTestRunner { BuildOptions.AddLifetime = true; // Run the main analysis. - Analysis = std::make_unique<LifetimeSafetyAnalysis>(*AnalysisCtx, nullptr, 0, 0); + Analysis = + std::make_unique<LifetimeSafetyAnalysis>(*AnalysisCtx, nullptr, 0); Analysis->run(); AnnotationToPointMap = Analysis->getFactManager().getTestPoints(); >From 3cb5ad3c341f2fa65bb74e50becb5d7e04b074c8 Mon Sep 17 00:00:00 2001 From: Debadri Basak <[email protected]> Date: Fri, 12 Dec 2025 09:11:33 +0000 Subject: [PATCH 6/6] Changing the flag name and removing unused dumpCFGStats function --- .../Analysis/Analyses/LifetimeSafety/Facts.h | 10 +---- .../Analyses/LifetimeSafety/LifetimeSafety.h | 9 ++--- clang/include/clang/Basic/LangOptions.def | 5 +-- clang/include/clang/Options/Options.td | 23 ++++++----- clang/lib/Analysis/LifetimeSafety/Checker.cpp | 3 +- clang/lib/Analysis/LifetimeSafety/Facts.cpp | 24 ----------- .../LifetimeSafety/LifetimeSafety.cpp | 40 ++++++++----------- clang/lib/Sema/AnalysisBasedWarnings.cpp | 3 +- 8 files changed, 38 insertions(+), 79 deletions(-) diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h index b10b0a95a82fa..82e14832208b3 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h @@ -218,10 +218,6 @@ class FactManager { void dump(const CFG &Cfg, AnalysisDeclContext &AC) const; - // A utility function to print the size of the CFG blocks in the analysis - // context. - void dumpBlockSizes(const CFG &Cfg, AnalysisDeclContext &AC) const; - /// Retrieves program points that were specially marked in the source code /// for testing. /// @@ -242,9 +238,7 @@ class FactManager { const LoanManager &getLoanMgr() const { return LoanMgr; } OriginManager &getOriginMgr() { return OriginMgr; } const OriginManager &getOriginMgr() const { return OriginMgr; } - void setBlockNumThreshold(uint32_t Threshold) { - BlockNumThreshold = Threshold; - } + void setMaxCFGBlocksThreshold(size_t Threshold) { MaxCFGBlocks = Threshold; } private: FactID NextFactID{0}; @@ -253,7 +247,7 @@ class FactManager { /// Facts for each CFG block, indexed by block ID. llvm::SmallVector<llvm::SmallVector<const Fact *>> BlockToFacts; llvm::BumpPtrAllocator FactAllocator; - uint32_t BlockNumThreshold = 0; + size_t MaxCFGBlocks = 0; }; } // namespace clang::lifetimes::internal diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h index e32e91befca8f..0173c872cbee6 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h @@ -52,8 +52,7 @@ class LifetimeSafetyReporter { /// The main entry point for the analysis. void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, - LifetimeSafetyReporter *Reporter, - uint32_t CfgBlocknumThreshold); + LifetimeSafetyReporter *Reporter); namespace internal { /// An object to hold the factories for immutable collections, ensuring @@ -69,8 +68,7 @@ struct LifetimeFactory { class LifetimeSafetyAnalysis { public: LifetimeSafetyAnalysis(AnalysisDeclContext &AC, - LifetimeSafetyReporter *Reporter, - uint32_t CfgBlocknumThreshold); + LifetimeSafetyReporter *Reporter, size_t MaxCFGBlocks); void run(); @@ -82,8 +80,7 @@ class LifetimeSafetyAnalysis { FactManager &getFactManager() { return FactMgr; } private: - bool shouldBailOutCFGPreFactGeneration(const CFG &Cfg) const; - uint32_t CfgBlocknumThreshold; + size_t MaxCFGBlocks; AnalysisDeclContext &AC; LifetimeSafetyReporter *Reporter; LifetimeFactory Factory; diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 05830caea2830..d8de6e3e8826c 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -499,10 +499,9 @@ LANGOPT(BoundsSafety, 1, 0, NotCompatible, "Bounds safety extension for C") LANGOPT(EnableLifetimeSafety, 1, 0, NotCompatible, "Experimental lifetime safety analysis for C++") -LANGOPT(PreserveVec3Type, 1, 0, NotCompatible, "Preserve 3-component vector type") - -LANGOPT(CfgBlocknumThreshold, 32, 0, NotCompatible, "Experimental CFG bailout size threshold for C++") +LANGOPT(LifetimeSafetyMaxCFGBlocks, 32, 0, NotCompatible, "Skip LifetimeSafety analysis for functions with CFG block count exceeding this threshold. Specify 0 for no limit") +LANGOPT(PreserveVec3Type, 1, 0, NotCompatible, "Preserve 3-component vector type") #undef LANGOPT #undef ENUM_LANGOPT diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 975d7bf0341a9..c208179925b87 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -1955,6 +1955,14 @@ defm lifetime_safety : BoolFOption< BothFlags<[], [CC1Option], " experimental lifetime safety for C++">>; +def fexperimental_lifetime_safety_max_cfg_blocks + : Joined<["-"], "fexperimental-lifetime-safety-max-cfg-blocks=">, + Group<m_Group>, + Visibility<[ClangOption, CC1Option]>, + HelpText<"Skip LifetimeSafety analysis for functions with CFG block " + "count exceeding this threshold. Specify 0 for no limit.">, + MarshallingInfoInt<LangOpts<"LifetimeSafetyMaxCFGBlocks">>; + defm addrsig : BoolFOption<"addrsig", CodeGenOpts<"Addrsig">, DefaultFalse, PosFlag<SetTrue, [], [ClangOption, CC1Option], "Emit">, @@ -5163,17 +5171,10 @@ def mmlir : Separate<["-"], "mmlir">, HelpText<"Additional arguments to forward to MLIR's option processing">, MarshallingInfoStringVector<FrontendOpts<"MLIRArgs">>; def ffuchsia_api_level_EQ : Joined<["-"], "ffuchsia-api-level=">, - Group<m_Group>, Visibility<[ClangOption, CC1Option]>, - HelpText<"Set Fuchsia API level">, - MarshallingInfoInt<LangOpts<"FuchsiaAPILevel">>; -def fcfg_block_num_threshold - : Joined<["-"], "fcfg-block-num-threshold=">, - Group<m_Group>, - Visibility<[ClangOption, CC1Option]>, - HelpText< - "Set Threshold for number of blocks above which lifetime analysis " - "will be skipped for a CFG">, - MarshallingInfoInt<LangOpts<"CfgBlocknumThreshold">>; + Group<m_Group>, + Visibility<[ClangOption, CC1Option]>, + HelpText<"Set Fuchsia API level">, + MarshallingInfoInt<LangOpts<"FuchsiaAPILevel">>; def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">, Visibility<[ClangOption, CC1Option, FlangOption]>, Group<m_Group>, HelpText<"Set macOS deployment target">; diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp index 0ced00f5fadda..1f7c282dadac2 100644 --- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp @@ -61,11 +61,10 @@ class LifetimeChecker { AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter) : LoanPropagation(LoanPropagation), LiveOrigins(LiveOrigins), FactMgr(FM), Reporter(Reporter) { - for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>()) { + for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>()) for (const Fact *F : FactMgr.getFacts(B)) if (const auto *EF = F->getAs<ExpireFact>()) checkExpiry(EF); - } issuePendingWarnings(); } diff --git a/clang/lib/Analysis/LifetimeSafety/Facts.cpp b/clang/lib/Analysis/LifetimeSafety/Facts.cpp index 9cdde1b4d77d9..0ae7111c489e8 100644 --- a/clang/lib/Analysis/LifetimeSafety/Facts.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Facts.cpp @@ -95,30 +95,6 @@ void FactManager::dump(const CFG &Cfg, AnalysisDeclContext &AC) const { } } -void FactManager::dumpBlockSizes(const CFG &Cfg, - AnalysisDeclContext &AC) const { - llvm::dbgs() << "==========================================\n"; - llvm::dbgs() << " Lifetime Analysis CFG Block Sizes:\n"; - llvm::dbgs() << "==========================================\n"; - if (const Decl *D = AC.getDecl()) - if (const auto *ND = dyn_cast<NamedDecl>(D)) - llvm::dbgs() << "Function: " << ND->getQualifiedNameAsString() << "\n"; - llvm::dbgs() << "Number of CFG Blocks: " << Cfg.getNumBlockIDs() << "\n"; - if (BlockNumThreshold > 0 && Cfg.getNumBlockIDs() > BlockNumThreshold) { - llvm::dbgs() << "CFG Block Number Threshold: " << BlockNumThreshold << "\n"; - llvm::dbgs() << "Bailed out before generating facts.\n"; - return; - } - // Print blocks in the order as they appear in code for a stable ordering. - for (const CFGBlock *B : *AC.getAnalysis<PostOrderCFGView>()) { - if (B->getLabel()) - llvm::dbgs() << " Block: " << B->getLabel()->getStmtClassName(); - else - llvm::dbgs() << " Block B" << B->getBlockID(); - llvm::dbgs() << ": Number of elements = " << B->size() << "\n"; - } -} - llvm::ArrayRef<const Fact *> FactManager::getBlockContaining(ProgramPoint P) const { for (const auto &BlockToFactsVec : BlockToFacts) { diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp index af3b3cc87f872..b74b2feb3174b 100644 --- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp @@ -28,36 +28,30 @@ #include "llvm/Support/TimeProfiler.h" #include <memory> -#undef DEBUG_TYPE -#define DEBUG_TYPE "lifetime-safety" - namespace clang::lifetimes { namespace internal { LifetimeSafetyAnalysis::LifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter, - uint32_t CfgBlocknumThreshold) - : CfgBlocknumThreshold(CfgBlocknumThreshold), AC(AC), Reporter(Reporter) { - FactMgr.setBlockNumThreshold(CfgBlocknumThreshold); -} - -bool LifetimeSafetyAnalysis::shouldBailOutCFGPreFactGeneration(const CFG& Cfg) const { - if ((CfgBlocknumThreshold > 0) && - (Cfg.getNumBlockIDs() > CfgBlocknumThreshold)) { - LLVM_DEBUG(llvm::dbgs() - << "Aborting Lifetime Safety analysis for current CFG as it has " - "blocks exceeding the thresold. Number of blocks: " - << Cfg.getNumBlockIDs() << "\n"); - return true; - } - return false; + size_t MaxCFGBlocks) + : MaxCFGBlocks(MaxCFGBlocks), AC(AC), Reporter(Reporter) { + FactMgr.setMaxCFGBlocksThreshold(MaxCFGBlocks); } void LifetimeSafetyAnalysis::run() { llvm::TimeTraceScope TimeProfile("LifetimeSafetyAnalysis"); const CFG &Cfg = *AC.getCFG(); - if (shouldBailOutCFGPreFactGeneration(Cfg)) { + if (MaxCFGBlocks > 0 && Cfg.getNumBlockIDs() > MaxCFGBlocks) { + std::string FuncName = "<unknown>"; + if (const Decl *D = AC.getDecl()) + if (const auto *ND = dyn_cast<NamedDecl>(D)) + FuncName = ND->getQualifiedNameAsString(); + DEBUG_WITH_TYPE("LifetimeSafety", + llvm::dbgs() + << "LifetimeSafety: Skipping function " << FuncName + << "due to large CFG: <count> blocks (threshold: " + << MaxCFGBlocks << ")\n"); return; } DEBUG_WITH_TYPE("PrintCFG", Cfg.dump(AC.getASTContext().getLangOpts(), @@ -67,7 +61,6 @@ void LifetimeSafetyAnalysis::run() { FactsGenerator FactGen(FactMgr, AC); FactGen.run(); DEBUG_WITH_TYPE("LifetimeFacts", FactMgr.dump(Cfg, AC)); - DEBUG_WITH_TYPE("LifetimeCFGSizes", FactMgr.dumpBlockSizes(Cfg, AC)); /// TODO(opt): Consider optimizing individual blocks before running the /// dataflow analysis. @@ -93,9 +86,10 @@ void LifetimeSafetyAnalysis::run() { } // namespace internal void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, - LifetimeSafetyReporter *Reporter, - uint32_t CfgBlocknumThreshold) { - internal::LifetimeSafetyAnalysis Analysis(AC, Reporter, CfgBlocknumThreshold); + LifetimeSafetyReporter *Reporter) { + internal::LifetimeSafetyAnalysis Analysis( + AC, Reporter, + AC.getASTContext().getLangOpts().LifetimeSafetyMaxCFGBlocks); Analysis.run(); } } // namespace clang::lifetimes diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 00d8e52bcbbea..43d2b9a829545 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -3107,8 +3107,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) { if (AC.getCFG()) { lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S); - lifetimes::runLifetimeSafetyAnalysis( - AC, &LifetimeSafetyReporter, S.getLangOpts().CfgBlocknumThreshold); + lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetyReporter); } } // Check for violations of "called once" parameter properties. _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
