From 8b852807022dedfc78394d33c66fb360ca6844df Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 17 Apr 2026 09:42:53 +0200 Subject: [PATCH 01/10] Decouple ICFG from analysis domain in IDESolver/IFDSSolver --- .../DataFlow/IfdsIde/EdgeFunctionStats.h | 5 +- .../DataFlow/IfdsIde/Solver/IDESolver.h | 63 ++++++++----------- .../DataFlow/IfdsIde/Solver/IFDSSolver.h | 42 ++++++------- .../Controller/AnalysisControllerInternal.h | 7 ++- .../AnalysisControllerInternalIDE.h | 56 ++++++++++------- 5 files changed, 85 insertions(+), 88 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunctionStats.h b/include/phasar/DataFlow/IfdsIde/EdgeFunctionStats.h index 448188b48b..14a0cb1451 100644 --- a/include/phasar/DataFlow/IfdsIde/EdgeFunctionStats.h +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunctionStats.h @@ -10,7 +10,8 @@ #ifndef PHASAR_DATAFLOW_IFDSIDE_EDGEFUNCTIONSTATS_H #define PHASAR_DATAFLOW_IFDSIDE_EDGEFUNCTIONSTATS_H -#include "llvm/ADT/StringRef.h" +#include "phasar/ControlFlow/ICFG.h" + #include "llvm/Support/raw_ostream.h" #include @@ -72,7 +73,7 @@ class EdgeFunctionStats : public detail::EdgeFunctionStatsData { const EdgeFunctionStats &S); private: - template + template friend class IDESolver; constexpr EdgeFunctionStats( diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index 3f1218d9dc..bd3f65aaf3 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -18,6 +18,7 @@ #define PHASAR_DATAFLOW_IFDSIDE_SOLVER_IDESOLVER_H #include "phasar/Config/Configuration.h" +#include "phasar/ControlFlow/ICFG.h" #include "phasar/ControlFlow/SparseCFGProvider.h" #include "phasar/DB/ProjectIRDBBase.h" #include "phasar/DataFlow/IfdsIde/EdgeFunction.h" @@ -49,7 +50,6 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/TypeName.h" #include "llvm/Support/raw_ostream.h" #include "nlohmann/json.hpp" @@ -61,7 +61,6 @@ #include #include #include -#include #include namespace psr { @@ -70,7 +69,8 @@ namespace psr { /// Sagiv, Horwitz and Reps. To solve the problem, call solve(). Results /// can then be queried by using resultAt() and resultsAt(). template > + typename Container = std::set, + ICFG ICFGTy = typename AnalysisDomainTy::i_t> class IDESolver : public IDESolverAPIMixin> { friend IDESolverAPIMixin>; @@ -82,27 +82,20 @@ class IDESolver using l_t = typename AnalysisDomainTy::l_t; using n_t = typename AnalysisDomainTy::n_t; - using i_t = typename AnalysisDomainTy::i_t; + using i_t = ICFGTy; using d_t = typename AnalysisDomainTy::d_t; using f_t = typename AnalysisDomainTy::f_t; using t_t = typename AnalysisDomainTy::t_t; using v_t = typename AnalysisDomainTy::v_t; - template I> IDESolver(IDETabulationProblem &Problem, - const I *ICF) + const ICFGTy *ICF) : IDEProblem(Problem), ZeroValue(Problem.getZeroValue()), - ICF(&static_cast(*ICF)), SVFG(ICF), + ICF(&assertNotNull(ICF)), SolverConfig(Problem.getIFDSIDESolverConfig()), CachedFlowEdgeFunctions(Problem), AllTop(Problem.allTopFunction()), JumpFn(std::make_shared>()), - Seeds(Problem.initialSeeds()) { - assert(ICF != nullptr); - - if constexpr (has_getSparseCFG_v) { - NextUserOrNullCB = &nextUserOrNullThunk; - } - } + Seeds(Problem.initialSeeds()) {} IDESolver(IDETabulationProblem *Problem, const i_t *ICF) @@ -351,13 +344,19 @@ class IDESolver } protected: - Nullable getNextUserOrNull(ByConstRef Fun, ByConstRef d3, - ByConstRef n) { - if (!NextUserOrNullCB || IDEProblem.isZeroValue(d3)) { + [[nodiscard]] Nullable getNextUserOrNull(ByConstRef Fun, + ByConstRef d3, + ByConstRef n) { + if constexpr (has_getSparseCFG_v) { + if (IDEProblem.isZeroValue(d3)) { + return {}; + } + + auto &&SCFG = ICF->getSparseCFG(Fun, d3); + return SCFG.nextUserOrNull(n); + } else { return {}; } - - return NextUserOrNullCB(SVFG, Fun, d3, n); } /// Lines 13-20 of the algorithm; processing a call site in the caller's @@ -1772,13 +1771,6 @@ class IDESolver } private: - template - static auto nextUserOrNullThunk(const void *SVFG, ByConstRef Fun, - ByConstRef d3, ByConstRef n) { - auto &&SCFG = static_cast(SVFG)->getSparseCFG(Fun, d3); - return SCFG.nextUserOrNull(n); - }; - /// @brief: Allows less-than comparison based on the statement ID. struct StmtLess { const i_t *ICF; @@ -1875,10 +1867,7 @@ class IDESolver IDETabulationProblem &IDEProblem; d_t ZeroValue; const i_t *ICF; - const void *SVFG; IFDSIDESolverConfig &SolverConfig; - Nullable (*NextUserOrNullCB)(const void *, ByConstRef, - ByConstRef, ByConstRef) = nullptr; std::vector, EdgeFunction>> WorkList; std::vector> ValuePropWL; @@ -1926,14 +1915,14 @@ operator<<(llvm::raw_ostream &OS, } template -IDESolver(Problem &, ICF *) +IDESolver(Problem &, const ICF *) -> IDESolver; + typename Problem::container_type, ICF>; template -IDESolver(Problem *, ICF *) +IDESolver(Problem *, const ICF *) -> IDESolver; + typename Problem::container_type, ICF>; template using IDESolver_P = IDESolver OwningSolverResults -solveIDEProblem( - IDETabulationProblem &Problem, - const std::convertible_to auto - &ICF) { - IDESolver Solver(&Problem, &ICF); +solveIDEProblem(IDETabulationProblem &Problem, + const ICFG auto &ICF) { + IDESolver Solver(&Problem, &ICF); Solver.solve(); return Solver.consumeSolverResults(); } diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h index 59055acdb3..a169cffc58 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h @@ -37,26 +37,28 @@ namespace psr { /// IFDSIDESolverConfig#setComputeValues(bool) to disable IDE's /// phase 2. template > -class IFDSSolver - : public IDESolver, Container> { + typename Container = std::set, + ICFG ICFGTy = typename AnalysisDomainTy::i_t> +class IFDSSolver : public IDESolver, + Container, ICFGTy> { + using Base = + IDESolver, Container, ICFGTy>; + public: using ProblemTy = IFDSTabulationProblem; using d_t = typename AnalysisDomainTy::d_t; using n_t = typename AnalysisDomainTy::n_t; - using i_t = typename AnalysisDomainTy::i_t; + using i_t = ICFGTy; - template IfdsDomainTy, - std::convertible_to I> + template IfdsDomainTy> IFDSSolver(IFDSTabulationProblem &IFDSProblem, - const I *ICF) - : IDESolver>(IFDSProblem, ICF) {} + const ICFGTy *ICF) + : Base(IFDSProblem, ICF) {} - template IfdsDomainTy, - std::convertible_to I> + template IfdsDomainTy> IFDSSolver(IFDSTabulationProblem *IFDSProblem, - const I *ICF) - : IDESolver>(IFDSProblem, ICF) {} + const ICFGTy *ICF) + : Base(IFDSProblem, ICF) {} ~IFDSSolver() override = default; @@ -110,13 +112,13 @@ class IFDSSolver }; template -IFDSSolver(Problem &, ICF *) +IFDSSolver(Problem &, const ICF *) -> IFDSSolver; + typename Problem::container_type, ICF>; template -IFDSSolver(Problem *, ICF *) +IFDSSolver(Problem *, const ICF *) -> IFDSSolver; + typename Problem::container_type, ICF>; template using IFDSSolver_P = IFDSSolver OwningSolverResults -solveIFDSProblem( - IFDSTabulationProblem &Problem, - const std::convertible_to auto - &ICF) { - IFDSSolver Solver(Problem, &ICF); +solveIFDSProblem(IFDSTabulationProblem &Problem, + const ICFG auto &ICF) { + IFDSSolver Solver(Problem, &ICF); Solver.solve(); return Solver.consumeSolverResults(); } diff --git a/tools/phasar-cli/Controller/AnalysisControllerInternal.h b/tools/phasar-cli/Controller/AnalysisControllerInternal.h index 42547dbff5..df935baf84 100644 --- a/tools/phasar-cli/Controller/AnalysisControllerInternal.h +++ b/tools/phasar-cli/Controller/AnalysisControllerInternal.h @@ -24,7 +24,7 @@ #include "AnalysisController.h" namespace psr { -template class IDESolver; +template class IDESolver; } // namespace psr namespace psr::controller { @@ -63,8 +63,9 @@ makeTaintConfig(AnalysisController &Data); template static void statsEmitter(llvm::raw_ostream & /*OS*/, const T & /*Solver*/) {} -template -static void statsEmitter(llvm::raw_ostream &OS, const IDESolver &Solver); +template +static void statsEmitter(llvm::raw_ostream &OS, + const IDESolver &Solver); template static void emitRequestedDataFlowResults(AnalysisController &Data, T &Solver) { diff --git a/tools/phasar-cli/Controller/AnalysisControllerInternalIDE.h b/tools/phasar-cli/Controller/AnalysisControllerInternalIDE.h index 80b9c3ef82..c986ccc01a 100644 --- a/tools/phasar-cli/Controller/AnalysisControllerInternalIDE.h +++ b/tools/phasar-cli/Controller/AnalysisControllerInternalIDE.h @@ -19,19 +19,16 @@ namespace psr::controller { -template -static void statsEmitter(llvm::raw_ostream &OS, const IDESolver &Solver) { +template +static void statsEmitter(llvm::raw_ostream &OS, + const IDESolver &Solver) { OS << "\nEdgeFunction Statistics:\n"; Solver.printEdgeFunctionStatistics(OS); } -template -static void executeIfdsIdeAnalysisImpl(AnalysisController &Data, - const ICFGTy &ICF, ArgTys &&...Args) { - auto Problem = - createAnalysisProblem(*Data.HA, std::forward(Args)...); - SolverTy Solver(Problem, &ICF); +template +static void executeIfdsIdeAnalysisImpl(SolverTy &Solver, + AnalysisController &Data) { { std::optional MeasureTime; if (Data.EmitterOptions & @@ -46,45 +43,56 @@ static void executeIfdsIdeAnalysisImpl(AnalysisController &Data, emitRequestedDataFlowResults(Data, Solver); } -template -static void executeIfdsIdeAnalysis(AnalysisController &Data, ArgTys &&...Args) { - executeIfdsIdeAnalysisImpl( - Data, Data.HA->getICFG(), std::forward(Args)...); -} - template static void executeSparseIfdsIdeAnalysis(AnalysisController &Data, ArgTys &&...Args) { - SparseLLVMBasedICFGView SVFG(&Data.HA->getICFG(), Data.HA->getAliasInfo()); executeIfdsIdeAnalysisImpl( Data, SVFG, std::forward(Args)...); } +template +static void executeIFDSAnalysisWithICFG(AnalysisController &Data, + const ICFG auto &ICF, + ArgTys &&...Args) { + auto Problem = + createAnalysisProblem(*Data.HA, std::forward(Args)...); + IFDSSolver Solver(&Problem, &ICF); + executeIfdsIdeAnalysisImpl(Solver, Data); +} +template +static void executeIDEAnalysisWithICFG(AnalysisController &Data, + const ICFG auto &ICF, ArgTys &&...Args) { + auto Problem = + createAnalysisProblem(*Data.HA, std::forward(Args)...); + IDESolver Solver(&Problem, &ICF); + executeIfdsIdeAnalysisImpl(Solver, Data); +} + template static void executeIFDSAnalysis(AnalysisController &Data, ArgTys &&...Args) { - executeIfdsIdeAnalysis, ProblemTy>( - Data, std::forward(Args)...); + executeIFDSAnalysisWithICFG(Data, Data.HA->getICFG(), + PSR_FWD(Args)...); } template static void executeSparseIFDSAnalysis(AnalysisController &Data, ArgTys &&...Args) { - executeSparseIfdsIdeAnalysis, ProblemTy>( - Data, std::forward(Args)...); + SparseLLVMBasedICFGView SVFG(&Data.HA->getICFG(), Data.HA->getAliasInfo()); + executeIFDSAnalysisWithICFG(Data, SVFG, PSR_FWD(Args)...); } template static void executeIDEAnalysis(AnalysisController &Data, ArgTys &&...Args) { - executeIfdsIdeAnalysis, ProblemTy>( - Data, std::forward(Args)...); + executeIDEAnalysisWithICFG(Data, Data.HA->getICFG(), + PSR_FWD(Args)...); } template static void executeSparseIDEAnalysis(AnalysisController &Data, ArgTys &&...Args) { - executeSparseIfdsIdeAnalysis, ProblemTy>( - Data, std::forward(Args)...); + SparseLLVMBasedICFGView SVFG(&Data.HA->getICFG(), Data.HA->getAliasInfo()); + executeIDEAnalysisWithICFG(Data, SVFG, PSR_FWD(Args)...); } } // namespace psr::controller From dfe2e276654ecfb9dcb45f328acd65c01bdbb38d Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 17 Apr 2026 09:54:46 +0200 Subject: [PATCH 02/10] Decouple ICFG from analysis domain in IterativeIDESolver --- .../IfdsIde/Solver/IterativeIDESolver.h | 56 ++++--------------- .../IfdsIde/IterativeIDESolverTest.cpp | 16 +++--- 2 files changed, 19 insertions(+), 53 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolver.h index bbd370a715..fc79c6e2b0 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolver.h @@ -54,7 +54,8 @@ namespace psr { /// () by Schiebel, Sattler, /// Schubert, Apel, and Bodden. template > + typename StaticSolverConfigTy = DefaultIDESolverConfig, + ICFG ICFGTy = typename ProblemTy::ProblemAnalysisDomain::i_t> class IterativeIDESolver : private SolverStatsSelector, private detail::IterativeIDESolverResults< @@ -68,9 +69,10 @@ class IterativeIDESolver typename StaticSolverConfigTy::template EdgeFunctionPtrType< typename ProblemTy::ProblemAnalysisDomain::l_t>>, public IDESolverAPIMixin< - IterativeIDESolver> { + IterativeIDESolver> { - friend IDESolverAPIMixin>; + friend IDESolverAPIMixin< + IterativeIDESolver>; public: using domain_t = typename ProblemTy::ProblemAnalysisDomain; @@ -81,7 +83,7 @@ class IterativeIDESolver using v_t = typename domain_t::v_t; using l_t = std::conditional_t; - using i_t = typename domain_t::i_t; + using i_t = ICFGTy; using config_t = StaticSolverConfigTy; @@ -124,30 +126,12 @@ class IterativeIDESolver using typename base_t::summaries_t; - static inline constexpr JumpFunctionGCMode EnableJumpFunctionGC = + static constexpr JumpFunctionGCMode EnableJumpFunctionGC = StaticSolverConfigTy::EnableJumpFunctionGC; - static inline ProblemTy &assertNotNull(ProblemTy *Problem) noexcept { - /// Dereferencing a nullptr is UB, so after initializing this->Problem the - /// null-check might be optimized away to the literal 'true'. - /// However, we still want to pass a pointer to the ctor to make clear that - /// the _reference_ of the problem is captured. - assert(Problem && - "IterativeIDESolver: The IDETabulationProblem must not be null!"); - return *Problem; - } - - static inline const i_t &assertNotNull(const i_t *ICFG) noexcept { - /// Dereferencing a nullptr is UB, so after initializing this->ICFG the - /// null-check might be optimized away to the literal 'true'. - /// However, we still want to pass a pointer to the ctor to make clear that - /// the _reference_ of the problem is captured. - assert(ICFG && "IterativeIDESolver: The ICFG must not be null!"); - return *ICFG; - } - public: - IterativeIDESolver(ProblemTy *Problem, const i_t *ICFG) noexcept + IterativeIDESolver(ProblemTy *Problem, const ICFGTy *ICFG, + StaticSolverConfigTy /*Config*/ = {}) noexcept : Problem(assertNotNull(Problem)), ICFG(assertNotNull(ICFG)) {} auto solve() & { @@ -369,8 +353,6 @@ class IterativeIDESolver } void performDataflowFactPropagation() { - // submitInitialSeeds(); - std::atomic_bool Finished = true; do { /// NOTE: Have a separate function on the worklist to process it, to @@ -869,10 +851,6 @@ class IterativeIDESolver auto ExitId = NodeCompressor.getOrInsert(ExitInst); if constexpr (!UseEndSummaryTab) { - // Summaries = JumpFunctions[ExitId].cellVec([FactId](const auto &Kvp) - // { - // return splitId(Kvp.first).first == FactId; - // }); Summaries = JumpFunctions[ExitId].allOf( [](uint64_t Key) { return splitId(Key).first; }, FactId, [](uint64_t Key) { return splitId(Key).second; }); @@ -911,7 +889,7 @@ class IterativeIDESolver for (ByConstRef SP : ICFG.getStartPointsOf(Callee)) { auto SPId = NodeCompressor.getOrInsert(SP); auto &JumpFn = JumpFunctions[SPId]; - // bool HasResults = !JumpFn.empty(); + for (ByConstRef Fact : CalleeFacts) { auto FactId = FactCompressor.getOrInsert(Fact); @@ -929,8 +907,6 @@ class IterativeIDESolver storeResultsAndPropagate(JumpFn, SPId, FactId, FactId, CalleeId, IdEF); - // CallWL.insert(combineIds(FactId, CalleeId)); - auto It = &AllInterPropagationsOwner.emplace_back(InterPropagationJob{ CallEF, SourceFactId, CalleeId, AtInstructionId, FactId}); auto Inserted = @@ -1081,10 +1057,6 @@ class IterativeIDESolver /// map we are iterating over is bad if constexpr (!UseEndSummaryTab) { - // Summaries = JumpFunctions[ExitId].cellVec( - // [SPFactId{SPFactId}](const auto &Kvp) { - // return splitId(Kvp.first).first == SPFactId; - // }); Summaries = JumpFunctions[ExitId].allOf( [](uint64_t Key) { return splitId(Key).first; }, SPFactId, [](uint64_t Key) { return splitId(Key).second; }); @@ -1311,8 +1283,6 @@ class IterativeIDESolver } void cleanupInterJobsFor(unsigned FunId) { - /// XXX: Use std::erase_if when upgrading to C++20 - auto Cells = SourceFactAndFuncToInterJob.cells(); for (auto Iter = Cells.begin(), End = Cells.end(); Iter != End;) { auto It = Iter++; @@ -1361,7 +1331,7 @@ class IterativeIDESolver } ProblemTy &Problem; - const i_t &ICFG; + const ICFGTy &ICFG; Compressor FunCompressor{}; @@ -1403,10 +1373,6 @@ class IterativeIDESolver llvm::OwningArrayRef RefCountPerFunction{}; llvm::BitVector CandidateFunctionsForGC{}; - // FlowFunctionCache FFCache{ - // &MRes}; - // EdgeFunctionCache EFCache{&MRes}; - flow_edge_function_cache_t FECache{Problem}; }; diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/IterativeIDESolverTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/IterativeIDESolverTest.cpp index d09e95d602..9be3438f64 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/IterativeIDESolverTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/IterativeIDESolverTest.cpp @@ -23,6 +23,8 @@ #include #include +#include + using namespace psr; /* ============== TEST FIXTURE ============== */ @@ -41,15 +43,14 @@ class IterativeIDESolverTest Soundness::Soundy, /*IncludeGlobals*/ true); IDELinearConstantAnalysis Problem(&IRDB, &ICFG, {"main"}); - IterativeIDESolver Solver( - &Problem, &ICFG); + IterativeIDESolver Solver(&Problem, &ICFG, SolverConfigTy{}); auto Start = std::chrono::steady_clock::now(); Solver.solve(); auto End = std::chrono::steady_clock::now(); auto NewTime = End - Start; - llvm::errs() << "IterativeIDESolver Elapsed:\t" << NewTime.count() - << "ns\n"; + llvm::errs() << llvm::getTypeName() << " Elapsed:\t" + << NewTime.count() << "ns\n"; IDESolver OldSolver(&Problem, &ICFG); Start = std::chrono::steady_clock::now(); @@ -89,16 +90,15 @@ class IterativeIDESolverTest Soundness::Soundy, /*IncludeGlobals*/ true); IDELinearConstantAnalysis Problem(&IRDB, &ICFG, {"main"}); - IterativeIDESolver Solver( - &Problem, &ICFG); + IterativeIDESolver Solver(&Problem, &ICFG, SolverConfigTy{}); auto Start = std::chrono::steady_clock::now(); std::atomic_bool Cancel = false; auto _ = Solver.solveWithAsyncCancellation(Cancel); auto End = std::chrono::steady_clock::now(); auto NewTime = End - Start; - llvm::errs() << "IterativeIDESolver Elapsed:\t" << NewTime.count() - << "ns\n"; + llvm::errs() << llvm::getTypeName() << " Elapsed:\t" + << NewTime.count() << "ns\n"; IDESolver OldSolver(&Problem, &ICFG); Start = std::chrono::steady_clock::now(); From c3031dcba65ed2237301f5fec7baccff9c97b9d3 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 17 Apr 2026 11:39:43 +0200 Subject: [PATCH 03/10] Better pretty-printing of StaticIDESolverConfig names --- .../IfdsIde/Solver/StaticIDESolverConfig.h | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/Solver/StaticIDESolverConfig.h b/include/phasar/DataFlow/IfdsIde/Solver/StaticIDESolverConfig.h index 4cf452be2c..2e546d2b0e 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/StaticIDESolverConfig.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/StaticIDESolverConfig.h @@ -25,13 +25,13 @@ enum class JumpFunctionGCMode { struct IDESolverConfigBase { template - static inline constexpr bool IsSimple1d = + static constexpr bool IsSimple1d = sizeof(std::pair) <= 32 && std::is_nothrow_move_constructible_v && std::is_nothrow_move_constructible_v && has_llvm_dense_map_info; template - static inline constexpr bool IsSimpleVal = + static constexpr bool IsSimpleVal = sizeof(T) <= 32 && std::is_nothrow_move_constructible_v && has_llvm_dense_map_info; @@ -51,23 +51,31 @@ struct IDESolverConfigBase { template using EdgeFunctionPtrType = EdgeFunction; - static inline constexpr bool AutoAddZero = true; - static inline constexpr bool EnableStatistics = false; - static inline constexpr JumpFunctionGCMode EnableJumpFunctionGC = + static constexpr bool AutoAddZero = true; + static constexpr bool EnableStatistics = false; + static constexpr JumpFunctionGCMode EnableJumpFunctionGC = JumpFunctionGCMode::Disabled; - static inline constexpr bool UseEndSummaryTab = false; + static constexpr bool UseEndSummaryTab = false; }; +template struct WithComputeValues; +using IDESolverConfig = WithComputeValues; +using IFDSSolverConfig = WithComputeValues; + template -struct WithComputeValues : Base { +struct [[clang::preferred_name(IDESolverConfig), + clang::preferred_name(IFDSSolverConfig)]] +WithComputeValues : Base { static constexpr bool ComputeValues = ComputeValuesVal; }; -template struct WithGCMode : Base { - static constexpr JumpFunctionGCMode EnableJumpFunctionGC = GCMode; -}; +template struct WithStats; +using IDESolverConfigWithStats = WithStats; +using IFDSSolverConfigWithStats = WithStats; -template struct WithStats : Base { +template +struct [[clang::preferred_name(IDESolverConfigWithStats), + clang::preferred_name(IFDSSolverConfigWithStats)]] WithStats : Base { static constexpr bool EnableStatistics = EnableStats; }; @@ -77,15 +85,18 @@ struct WithWorkList : Base { }; template struct WithEndSummaryTab : Base { - static inline constexpr bool UseEndSummaryTab = UseEST; + static constexpr bool UseEndSummaryTab = UseEST; }; -using IDESolverConfig = WithComputeValues; -using IFDSSolverConfig = WithComputeValues; -using IDESolverConfigWithStats = WithStats; -using IFDSSolverConfigWithStats = WithStats; +template struct WithGCMode; + using IFDSSolverConfigWithStatsAndGC = WithGCMode; +template +struct [[clang::preferred_name(IFDSSolverConfigWithStatsAndGC)]] WithGCMode + : Base { + static constexpr JumpFunctionGCMode EnableJumpFunctionGC = GCMode; +}; template struct DefaultIDESolverConfig : IDESolverConfig {}; From 6c9d38c242e6acaec3d2a0e4f6abf9a449ff1900 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 17 Apr 2026 11:40:51 +0200 Subject: [PATCH 04/10] Use EndSummaryTab by default in IterativeIDESolver --- include/phasar/DataFlow/IfdsIde/Solver/StaticIDESolverConfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/phasar/DataFlow/IfdsIde/Solver/StaticIDESolverConfig.h b/include/phasar/DataFlow/IfdsIde/Solver/StaticIDESolverConfig.h index 2e546d2b0e..e4fe5b6ca5 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/StaticIDESolverConfig.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/StaticIDESolverConfig.h @@ -55,7 +55,7 @@ struct IDESolverConfigBase { static constexpr bool EnableStatistics = false; static constexpr JumpFunctionGCMode EnableJumpFunctionGC = JumpFunctionGCMode::Disabled; - static constexpr bool UseEndSummaryTab = false; + static constexpr bool UseEndSummaryTab = true; }; template struct WithComputeValues; From eabc9d61f5141491b9cda1b7a93ff209038ba726 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sat, 18 Apr 2026 12:52:52 +0200 Subject: [PATCH 05/10] Fix IFDSSolver ctor --- .github/workflows/ci.yml | 2 +- include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h | 10 +++++++--- .../DataFlow/IfdsIde/IterativeIDESolverTest.cpp | 3 +-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7cf419c0e3..7e3a85c14e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,7 +91,7 @@ jobs: cmake -DCMAKE_INSTALL_PREFIX=./INSTALL -P ./build/cmake_install.cmake PHASAR_ROOT_DIR=$(pwd) cd ./examples/how-to - cmake -S . -B build -Dphasar_ROOT="$PHASAR_ROOT_DIR/INSTALL" + cmake -S . -B build -G Ninja -Dphasar_ROOT="$PHASAR_ROOT_DIR/INSTALL" cmake --build ./build --target run_sample_programs - name: Check test coverage and generate HTML report diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h index a169cffc58..67d7f895df 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h @@ -50,12 +50,16 @@ class IFDSSolver : public IDESolver, using n_t = typename AnalysisDomainTy::n_t; using i_t = ICFGTy; - template IfdsDomainTy> + template + requires(std::same_as, + WithBinaryValueDomain>) IFDSSolver(IFDSTabulationProblem &IFDSProblem, const ICFGTy *ICF) : Base(IFDSProblem, ICF) {} - template IfdsDomainTy> + template + requires(std::same_as, + WithBinaryValueDomain>) IFDSSolver(IFDSTabulationProblem *IFDSProblem, const ICFGTy *ICF) : Base(IFDSProblem, ICF) {} @@ -129,7 +133,7 @@ OwningSolverResults solveIFDSProblem(IFDSTabulationProblem &Problem, const ICFG auto &ICF) { - IFDSSolver Solver(Problem, &ICF); + IFDSSolver Solver(&Problem, &ICF); Solver.solve(); return Solver.consumeSolverResults(); } diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/IterativeIDESolverTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/IterativeIDESolverTest.cpp index 9be3438f64..5547d4231d 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/IterativeIDESolverTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/IterativeIDESolverTest.cpp @@ -15,6 +15,7 @@ #include "phasar/Utils/Printer.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/Support/TypeName.h" #include "TestConfig.h" #include "gtest/gtest.h" @@ -23,8 +24,6 @@ #include #include -#include - using namespace psr; /* ============== TEST FIXTURE ============== */ From 7595c45b16987d44ddf943a3791ccbea0d7ee9b4 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sat, 18 Apr 2026 13:01:26 +0200 Subject: [PATCH 06/10] Deprecate IDE/IFDSSolver_P typedefs --- .../phasar/DataFlow/IfdsIde/Solver/IDESolver.h | 7 +++++-- .../phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h | 7 +++++-- .../Problems/IDEExtendedTaintAnalysisTest.cpp | 9 ++++----- .../IfdsIde/Problems/IDETSAnalysisFileIOTest.cpp | 5 +---- .../IDETSAnalysisOpenSSLSecureMemoryTest.cpp | 16 +++++++--------- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index bd3f65aaf3..70439fb56b 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -1925,8 +1925,11 @@ IDESolver(Problem *, const ICF *) typename Problem::container_type, ICF>; template -using IDESolver_P = IDESolver; +using IDESolver_P + [[deprecated("Let C++ deduce the template arguments of IDESolver, or call " + "solveIDEProblem() instead")]] = + IDESolver; template OwningSolverResults; template -using IFDSSolver_P = IFDSSolver; +using IFDSSolver_P + [[deprecated("Let C++ deduce the template arguments of IFDSSolver, or call " + "solveIFDSProblem() instead")]] = + IFDSSolver; template OwningSolverResults &TaintProblem, - IDESolver_P> &Solver, + compareResults(IDEExtendedTaintAnalysis<> &TaintProblem, auto &&SR, const std::map &GroundTruth) { auto GroundTruthEntries = convertTestingLocationSetMapInIR( GroundTruth, *TaintProblem.getProjectIRDB()); @@ -94,8 +94,7 @@ class IDETaintAnalysisTest : public ::testing::Test { std::map> FoundLeaks; - for (const auto &[LeakInst, LeakVals] : - TaintProblem.getAllLeaks(Solver.getSolverResults())) { + for (const auto &[LeakInst, LeakVals] : TaintProblem.getAllLeaks(SR)) { FoundLeaks[LeakInst].insert(LeakVals.begin(), LeakVals.end()); } diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisFileIOTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisFileIOTest.cpp index 0b4ff582ca..1d7bc8bd13 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisFileIOTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisFileIOTest.cpp @@ -90,10 +90,7 @@ class IDETSAnalysisFileIOTest : public ::testing::Test { * @param groundTruth results to compare against * @param solver provides the results */ - void compareResults( - const GroundTruthMapTy &GroundTruth, - IDESolver_P> - &Solver) { + void compareResults(const GroundTruthMapTy &GroundTruth, auto &Solver) { auto GroundTruthEntries = convertTestingLocationMapMapInIR(GroundTruth, HA->getProjectIRDB()); diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureMemoryTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureMemoryTest.cpp index c56fcd8db0..1af0cd0c0e 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureMemoryTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureMemoryTest.cpp @@ -8,6 +8,7 @@ *****************************************************************************/ #include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" +#include "phasar/DataFlow/IfdsIde/SolverResults.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h" @@ -36,9 +37,10 @@ class IDETSAnalysisOpenSSLSecureMemoryTest : public ::testing::Test { std::optional HA; OpenSSLSecureMemoryDescription Desc{}; std::optional> TSProblem; - std::unique_ptr< - IDESolver_P>> - Llvmtssolver; + std::optional< + OwningSolverResults> + SR; enum OpenSSLSecureMemoryState { TOP = 42, @@ -55,11 +57,7 @@ class IDETSAnalysisOpenSSLSecureMemoryTest : public ::testing::Test { TSProblem = createAnalysisProblem< IDETypeStateAnalysis>(*HA, &Desc, EntryPoints); - Llvmtssolver = std::make_unique< - IDESolver_P>>( - *TSProblem, &HA->getICFG()); - - Llvmtssolver->solve(); + SR = solveIDEProblem(*TSProblem, HA->getICFG()); } /** @@ -75,7 +73,7 @@ class IDETSAnalysisOpenSSLSecureMemoryTest : public ::testing::Test { auto *Inst = HA->getProjectIRDB().getInstruction(InstToGroundTruth.first); auto GT = InstToGroundTruth.second; std::map Results; - for (auto Result : Llvmtssolver->resultsAt(Inst, true)) { + for (auto Result : SR->resultsAt(Inst, true)) { if (GT.find(getMetaDataID(Result.first)) != GT.end()) { Results.insert(std::pair( getMetaDataID(Result.first), int(Result.second))); From 6b338848c8c4777b97522a35e59d0438431fc493 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sat, 18 Apr 2026 13:14:29 +0200 Subject: [PATCH 07/10] Fix deprecation warnings with IFDSSolver_P --- .../IfdsIde/Problems/IFDSConstAnalysisTest.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysisTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysisTest.cpp index 07c5187024..92a1a891d1 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysisTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysisTest.cpp @@ -56,11 +56,11 @@ class IFDSConstAnalysisTest : public ::testing::Test { } void compareResultsImpl(const std::set &GroundTruth, - IFDSSolver_P &Solver) { + auto &&SR) { std::set AllMutableAllocas; for (const auto *RR : getRetOrResInstructions()) { - std::set Facts = Solver.ifdsResultsAt(RR); + std::set Facts = SR.ifdsResultsAt(RR); for (const auto *Fact : Facts) { if (isAllocaInstOrHeapAllocaFunction(Fact) || (llvm::isa(Fact) && @@ -75,18 +75,18 @@ class IFDSConstAnalysisTest : public ::testing::Test { } void compareResults(const std::set &GroundTruth, - IFDSSolver_P &Solver) { + auto &Solver) { auto GroundTruthEntries = convertTestingLocationSetInIR(GroundTruth, HA->getProjectIRDB()); - compareResultsImpl(GroundTruthEntries, Solver); + compareResultsImpl(GroundTruthEntries, Solver.getSolverResults()); } void compareResults(std::initializer_list GroundTruth, - IFDSSolver_P &Solver) { + auto &Solver) { auto GroundTruthEntries = convertTestingLocationSetInIR(GroundTruth, HA->getProjectIRDB()); - compareResultsImpl(GroundTruthEntries, Solver); + compareResultsImpl(GroundTruthEntries, Solver.getSolverResults()); } }; From aceaabfd1e072a1884e10ea9b7d26d5b949ed775 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sat, 18 Apr 2026 13:18:51 +0200 Subject: [PATCH 08/10] minor --- .../PhasarLLVM/DataFlow/IfdsIde/SparseIDESolverTest.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/SparseIDESolverTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/SparseIDESolverTest.cpp index 3abcd460da..d0b22830c8 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/SparseIDESolverTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/SparseIDESolverTest.cpp @@ -1,6 +1,7 @@ #include "phasar/ControlFlow/CallGraphAnalysisType.h" #include "phasar/ControlFlow/SparseCFGProvider.h" #include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" +#include "phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" #include "phasar/PhasarLLVM/ControlFlow/SparseLLVMBasedCFG.h" #include "phasar/PhasarLLVM/ControlFlow/SparseLLVMBasedICFG.h" @@ -50,8 +51,8 @@ TEST_P(LinearConstant, SparseResultsEquivalent) { IDELinearConstantAnalysis LCAProblem(&IRDB, &ICF, Entry); IDELinearConstantAnalysis SLCAProblem(&IRDB, &SICF, Entry); - auto DenseResults = IDESolver(LCAProblem, &ICF).solve(); - auto SparseResults = IDESolver(SLCAProblem, &SICF).solve(); + auto DenseResults = IDESolver(&LCAProblem, &ICF).solve(); + auto SparseResults = IDESolver(&SLCAProblem, &SICF).solve(); DenseResults.dumpResults(ICF, llvm::outs() << "DenseResults:"); SparseResults.dumpResults(SICF, llvm::outs() << "SparseResults:"); @@ -102,8 +103,8 @@ TEST_P(DoubleFreeTA, SparseLeaksEquivalent) { IFDSTaintAnalysis TaintProblem(&IRDB, &PT, &Config, Entry); IFDSTaintAnalysis STaintProblem(&IRDB, &PT, &Config, Entry); - auto DenseResults = IDESolver(TaintProblem, &ICF).solve(); - auto SparseResults = IDESolver(STaintProblem, &SICF).solve(); + auto DenseResults = IFDSSolver(&TaintProblem, &ICF).solve(); + auto SparseResults = IFDSSolver(&STaintProblem, &SICF).solve(); for (const auto &[LeakInst, Leaks] : TaintProblem.Leaks) { auto LeakIt = STaintProblem.Leaks.find(LeakInst); From b9aee1894feecbf9cdf2cb49837d730f0a99d134 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sat, 18 Apr 2026 15:18:16 +0200 Subject: [PATCH 09/10] Fix invalid CRTP instantiation in IDESolver + update PathAwareIDESolver --- .../DataFlow/IfdsIde/Solver/IDESolver.h | 18 +++++------ .../IfdsIde/Solver/IDESolverAPIMixin.h | 3 ++ .../IfdsIde/Solver/PathAwareIDESolver.h | 30 +++++++++++++------ 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index 70439fb56b..6de6322b8d 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -72,8 +72,8 @@ template , ICFG ICFGTy = typename AnalysisDomainTy::i_t> class IDESolver - : public IDESolverAPIMixin> { - friend IDESolverAPIMixin>; + : public IDESolverAPIMixin> { + friend IDESolverAPIMixin>; public: using ProblemTy = IDETabulationProblem; @@ -1770,6 +1770,12 @@ class IDESolver OS << G; } + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const IDESolver &Solver) { + Solver.dumpResults(OS); + return OS; + } + private: /// @brief: Allows less-than comparison based on the statement ID. struct StmtLess { @@ -1906,14 +1912,6 @@ class IDESolver std::map, size_t> FSummaryReuse; }; -template -llvm::raw_ostream & -operator<<(llvm::raw_ostream &OS, - const IDESolver &Solver) { - Solver.dumpResults(OS); - return OS; -} - template IDESolver(Problem &, const ICF *) -> IDESolver class IDESolverAPIMixin { } private: + friend Derived; + constexpr IDESolverAPIMixin() noexcept = default; + [[nodiscard]] constexpr Derived &self() & noexcept { static_assert(std::is_base_of_v, "Invalid CRTP instantiation"); diff --git a/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h index b8c0912152..5caede846d 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h @@ -18,9 +18,11 @@ namespace psr { template > -class PathAwareIDESolver : public IDESolver { - using base_t = IDESolver; + typename Container = std::set, + ICFG ICFGTy = typename AnalysisDomainTy::i_t> +class PathAwareIDESolver + : public IDESolver { + using base_t = IDESolver; public: using domain_t = AnalysisDomainTy; @@ -30,10 +32,10 @@ class PathAwareIDESolver : public IDESolver { using container_type = typename base_t::container_type; explicit PathAwareIDESolver( - IDETabulationProblem &Problem, const i_t *ICF) - : base_t(Problem, ICF), ESG(Problem.getZeroValue()) { + IDETabulationProblem *Problem, const i_t *ICF) + : base_t(Problem, ICF), ESG(Problem->getZeroValue()) { - if (Problem.getIFDSIDESolverConfig().autoAddZero()) { + if (Problem->getIFDSIDESolverConfig().autoAddZero()) { PHASAR_LOG_LEVEL( WARNING, "The PathAwareIDESolver is initialized with the option 'autoAddZero' " @@ -41,6 +43,10 @@ class PathAwareIDESolver : public IDESolver { } } + explicit PathAwareIDESolver( + IDETabulationProblem &Problem, const i_t *ICF) + : PathAwareIDESolver(&Problem, ICF) {} + [[nodiscard]] const ExplodedSuperGraph & getExplicitESG() const & noexcept { return ESG; @@ -60,9 +66,15 @@ class PathAwareIDESolver : public IDESolver { ExplodedSuperGraph ESG; }; -template -PathAwareIDESolver(ProblemTy &) - -> PathAwareIDESolver; +template +PathAwareIDESolver(ProblemTy &, const ICFGTy *) + -> PathAwareIDESolver; + +template +PathAwareIDESolver(ProblemTy *, const ICFGTy *) + -> PathAwareIDESolver; } // namespace psr From a0aa9587c51beb79f4e99cf591ccf5b232683257 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sat, 18 Apr 2026 15:26:40 +0200 Subject: [PATCH 10/10] minor --- include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index 8cfe9ec97c..bd258d58a1 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -1776,12 +1776,6 @@ class IDESolver OS << G; } - friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const IDESolver &Solver) { - Solver.dumpResults(OS); - return OS; - } - private: /// @brief: Allows less-than comparison based on the statement ID. struct StmtLess {