Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Checks: '-*,
-readability-use-anyofallof,
-readability-avoid-return-with-void-value,
-readability-use-std-min-max,
-readability-math-missing-parentheses,
cppcoreguidelines-*,
-cppcoreguidelines-avoid-non-const-global-variables,
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
Expand All @@ -38,6 +39,7 @@ Checks: '-*,
-modernize-use-trailing-return-type,
-modernize-avoid-c-arrays,
performance-*,
-performance-enum-size,
clang-analyzer-*
'

Expand Down
81 changes: 65 additions & 16 deletions include/phasar/DataFlow/IfdsIde/Solver/IterativeIDESolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "phasar/ControlFlow/SparseCFGProvider.h"
#include "phasar/DataFlow/IfdsIde/EdgeFunctions.h"
#include "phasar/DataFlow/IfdsIde/Solver/Compressor.h"
#include "phasar/DataFlow/IfdsIde/Solver/ESGEdgeKind.h"
#include "phasar/DataFlow/IfdsIde/Solver/EdgeFunctionCache.h"
#include "phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCacheNG.h"
#include "phasar/DataFlow/IfdsIde/Solver/FlowFunctionCache.h"
Expand All @@ -18,11 +19,13 @@
#include "phasar/Domain/BinaryDomain.h"
#include "phasar/Utils/ByRef.h"
#include "phasar/Utils/EmptyBaseOptimizationUtils.h"
#include "phasar/Utils/Lazy.h"
#include "phasar/Utils/Logger.h"
#include "phasar/Utils/Printer.h"
#include "phasar/Utils/StableVector.h"
#include "phasar/Utils/TableWrappers.h"
#include "phasar/Utils/TypeTraits.h"
#include "phasar/Utils/Utilities.h"

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMapInfo.h"
Expand All @@ -40,6 +43,7 @@
#include <atomic>
#include <chrono>
#include <cstdint>
#include <iterator>
#include <memory>
#include <string>
#include <type_traits>
Expand Down Expand Up @@ -133,7 +137,8 @@ class IterativeIDESolver
public:
IterativeIDESolver(ProblemTy *Problem, const ICFGTy *ICFG,
StaticSolverConfigTy /*Config*/ = {}) noexcept
: Problem(assertNotNull(Problem)), ICFG(assertNotNull(ICFG)) {}
: Problem(assertNotNull(Problem)), ICFG(assertNotNull(ICFG)),
PathData(StaticSolverConfigTy::initPathData(assertNotNull(Problem))) {}

auto solve() & {
solveImpl();
Expand All @@ -158,6 +163,16 @@ class IterativeIDESolver
getSolverResults().dumpResults(ICFG, OS);
}

[[nodiscard]] const auto &getPathAwareData() const & noexcept {
return PathData;
}
[[nodiscard]] auto getPathAwareData() && noexcept {
return std::move(PathData);
}
[[nodiscard]] auto consumePathAwareData() noexcept {
return std::move(PathData);
}

[[nodiscard]] IterativeIDESolverStats getStats() const noexcept
requires EnableStatistics
{
Expand Down Expand Up @@ -651,6 +666,8 @@ class IterativeIDESolver
combineIds(AtInstructionId, SuccId))
.computeTargets(CSFact);

saveEdges(AtInstruction, Succ, CSFact, Facts, ESGEdgeKind::Normal);

for (ByConstRef<d_t> Fact : Facts) {
auto FactId = FactCompressor.getOrInsert(Fact);
auto EF = [&] {
Expand Down Expand Up @@ -697,20 +714,21 @@ class IterativeIDESolver
EdgeFunctionPtrType SourceEF, uint32_t FunId) {
const auto &Callees = ICFG.getCalleesOfCallAt(AtInstruction);

applyCallToReturnFlow(AtInstruction, AtInstructionId, SourceFactId,
PropagatedFactId, SourceEF, Callees, FunId);
bool HasNoCalleeInformation =
handleOrDeferCallFlow(AtInstruction, AtInstructionId, SourceFactId,
PropagatedFactId, SourceEF, Callees, FunId);

handleOrDeferCallFlow(AtInstruction, AtInstructionId, SourceFactId,
PropagatedFactId, std::move(SourceEF), Callees,
FunId);
applyCallToReturnFlow(AtInstruction, AtInstructionId, SourceFactId,
PropagatedFactId, std::move(SourceEF), Callees, FunId,
HasNoCalleeInformation);
}

template <typename CalleesTy>
void applyCallToReturnFlow(ByConstRef<n_t> AtInstruction,
uint32_t AtInstructionId, uint32_t SourceFactId,
uint32_t PropagatedFactId,
EdgeFunctionPtrType SourceEF,
const CalleesTy &Callees, uint32_t FunId) {
void
applyCallToReturnFlow(ByConstRef<n_t> AtInstruction, uint32_t AtInstructionId,
uint32_t SourceFactId, uint32_t PropagatedFactId,
EdgeFunctionPtrType SourceEF, const CalleesTy &Callees,
uint32_t FunId, bool HasNoCalleeInformation) {
auto CSFact = FactCompressor[PropagatedFactId];

for (ByConstRef<n_t> RetSite : ICFG.getReturnSitesOfCallAt(AtInstruction)) {
Expand All @@ -721,6 +739,10 @@ class IterativeIDESolver
combineIds(AtInstructionId, RetSiteId))
.computeTargets(CSFact);

saveEdges(AtInstruction, RetSite, CSFact, Facts,
HasNoCalleeInformation ? ESGEdgeKind::SkipUnknownFn
: ESGEdgeKind::CallToRet);

for (ByConstRef<d_t> Fact : Facts) {
auto FactId = FactCompressor.getOrInsert(Fact);

Expand All @@ -745,12 +767,13 @@ class IterativeIDESolver
}

template <typename CalleesTy>
void handleOrDeferCallFlow(ByConstRef<n_t> AtInstruction,
bool handleOrDeferCallFlow(ByConstRef<n_t> AtInstruction,
uint32_t AtInstructionId, uint32_t SourceFactId,
uint32_t PropagatedFactId,
EdgeFunctionPtrType SourceEF,
const CalleesTy &Callees, uint32_t FunId) {
auto CSFact = FactCompressor[PropagatedFactId];
bool HasNoCalleeInformation = true;
for (ByConstRef<f_t> Callee : Callees) {
auto CalleeId = FunCompressor.getOrInsert(Callee);
auto SummaryFF =
Expand All @@ -760,16 +783,19 @@ class IterativeIDESolver
if (SummaryFF == nullptr) {
/// No summary. Start inTRA propagation for the callee and defer
/// return-propagation
deferCallFlow(AtInstruction, AtInstructionId, SourceFactId, CSFact,
PropagatedFactId, SourceEF, Callee, CalleeId, FunId);
HasNoCalleeInformation =
deferCallFlow(AtInstruction, AtInstructionId, SourceFactId, CSFact,
PropagatedFactId, SourceEF, Callee, CalleeId, FunId);
} else {
HasNoCalleeInformation = false;
/// Apply SummaryFF and ignore this CSCallee pair in the
/// inter-propagation
applySummaryFlow(SummaryFF.computeTargets(CSFact), AtInstruction,
AtInstructionId, SourceFactId, CSFact,
PropagatedFactId, SourceEF, FunId);
}
}
return HasNoCalleeInformation;
}

void countSummaryLinearSearch(size_t SearchLen, size_t NumSummaries) {
Expand Down Expand Up @@ -837,7 +863,7 @@ class IterativeIDESolver
}
}

void deferCallFlow(ByConstRef<n_t> AtInstruction, uint32_t AtInstructionId,
bool deferCallFlow(ByConstRef<n_t> AtInstruction, uint32_t AtInstructionId,
uint32_t SourceFactId, ByConstRef<d_t> CSFact,
uint32_t CSFactId, EdgeFunctionPtrType SourceEF,
ByConstRef<f_t> Callee, uint32_t CalleeId,
Expand All @@ -855,9 +881,15 @@ class IterativeIDESolver
return EdgeFunctionPtrType{};
}
}();
for (ByConstRef<n_t> SP : ICFG.getStartPointsOf(Callee)) {

auto &&StartPoints = ICFG.getStartPointsOf(Callee);
bool HasNoCalleeInformation = std::empty(StartPoints);

for (ByConstRef<n_t> SP : StartPoints) {
auto SPId = NodeCompressor.getOrInsert(SP);

saveEdges(AtInstruction, SP, CSFact, CalleeFacts, ESGEdgeKind::Call);

for (ByConstRef<d_t> Fact : CalleeFacts) {
auto FactId = FactCompressor.getOrInsert(Fact);

Expand Down Expand Up @@ -906,6 +938,7 @@ class IterativeIDESolver
}
}
}
return HasNoCalleeInformation;
}

template <typename SummaryFactsTy>
Expand All @@ -917,6 +950,9 @@ class IterativeIDESolver
for (ByConstRef<n_t> RetSite : ICFG.getReturnSitesOfCallAt(AtInstruction)) {
auto RetSiteId = NodeCompressor.getOrInsert(RetSite);

saveEdges(AtInstruction, RetSite, CSFact, SummaryFacts,
ESGEdgeKind::Summary);

for (ByConstRef<d_t> Fact : SummaryFacts) {
auto FactId = FactCompressor.getOrInsert(Fact);

Expand Down Expand Up @@ -954,6 +990,9 @@ class IterativeIDESolver
uint32_t SummaryFactId{Summary.first};
auto SummaryFact = FactCompressor[SummaryFactId];
auto RetFacts = RetFF.computeTargets(SummaryFact);

saveEdges(ExitInst, RetSite, SummaryFact, RetFacts, ESGEdgeKind::Ret);

for (ByConstRef<d_t> RetFact : RetFacts) {
auto RetFactId = FactCompressor.getOrInsert(RetFact);

Expand Down Expand Up @@ -1288,6 +1327,13 @@ class IterativeIDESolver
}
}

void saveEdges(ByConstRef<n_t> SourceNode, ByConstRef<n_t> SinkStmt,
ByConstRef<d_t> SourceVal, const auto &DestVals,
ESGEdgeKind Kind) {
StaticSolverConfigTy::template saveEdges<domain_t>(
PathData, SourceNode, SinkStmt, SourceVal, DestVals, Kind);
}

static constexpr uint64_t combineIds(uint32_t LHS, uint32_t RHS) noexcept {
return (uint64_t(LHS) << 32) | RHS;
}
Expand Down Expand Up @@ -1339,6 +1385,9 @@ class IterativeIDESolver
llvm::BitVector CandidateFunctionsForGC{};

flow_edge_function_cache_t FECache{Problem};

[[no_unique_address]]
typename config_t::template PathTrackingData<domain_t> PathData;
};

} // namespace psr
Expand Down
63 changes: 63 additions & 0 deletions include/phasar/DataFlow/IfdsIde/Solver/PathAwareIterIDESolver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#pragma once

/******************************************************************************
* Copyright (c) 2026 Fabian Schiebel.
* All rights reserved. This program and the accompanying materials are made
* available under the terms of LICENSE.txt.
*
* Contributors:
* Fabian Schiebel and others
*****************************************************************************/

#include "phasar/DataFlow/IfdsIde/Solver/IterativeIDESolver.h"
#include "phasar/DataFlow/IfdsIde/Solver/StaticIDESolverConfig.h"
#include "phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h"

namespace psr {
template <typename Base> struct PathAwareIDESolverConfig : public Base {
template <typename AnalysisDomainTy>
using PathTrackingData = ExplodedSuperGraph<AnalysisDomainTy>;

template <typename ProblemTy>
static PathTrackingData<typename ProblemTy::ProblemAnalysisDomain>
initPathData(ProblemTy &Problem) {
return ExplodedSuperGraph<typename ProblemTy::ProblemAnalysisDomain>(
Problem.getZeroValue());
}

template <typename AnalysisDomainTy>
static void saveEdges(PathTrackingData<AnalysisDomainTy> &Data,
ByConstRef<typename AnalysisDomainTy::n_t> Curr,
ByConstRef<typename AnalysisDomainTy::n_t> Succ,
ByConstRef<typename AnalysisDomainTy::d_t> CurrNode,
const auto &SuccNodes, ESGEdgeKind Kind) {
Data.saveEdges(Curr, CurrNode, Succ, SuccNodes, Kind);
}
};

template <typename ProblemTy,
typename StaticSolverConfigTy = DefaultIDESolverConfig<ProblemTy>,
ICFG ICFGTy = typename ProblemTy::ProblemAnalysisDomain::i_t>
class PathAwareIterIDESolver
: public IterativeIDESolver<
ProblemTy, PathAwareIDESolverConfig<StaticSolverConfigTy>, ICFGTy> {
public:
using IterativeIDESolver<ProblemTy,
PathAwareIDESolverConfig<StaticSolverConfigTy>,
ICFGTy>::IterativeIDESolver;

[[nodiscard]] decltype(auto) getExplicitESG() const & noexcept {
return this->getPathAwareData();
}

[[nodiscard]] decltype(auto) getExplicitESG() && noexcept {
return std::move(*this).getPathAwareData();
}
};

template <typename ProblemTy, typename ICFGTy>
PathAwareIterIDESolver(ProblemTy *, ICFGTy *)
-> PathAwareIterIDESolver<ProblemTy, DefaultIDESolverConfig<ProblemTy>,
ICFGTy>;

} // namespace psr
19 changes: 19 additions & 0 deletions include/phasar/DataFlow/IfdsIde/Solver/StaticIDESolverConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
#define PHASAR_DATAFLOW_IFDSIDE_SOLVER_STATICIDESOLVERCONFIG_H

#include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h"
#include "phasar/DataFlow/IfdsIde/Solver/ESGEdgeKind.h"
#include "phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCacheNG.h"
#include "phasar/DataFlow/IfdsIde/Solver/WorkListTraits.h"
#include "phasar/Utils/EmptyBaseOptimizationUtils.h"
#include "phasar/Utils/TableWrappers.h"
#include "phasar/Utils/TypeTraits.h"

#include <concepts>
#include <type_traits>
#include <utility>

Expand Down Expand Up @@ -51,6 +54,22 @@ struct IDESolverConfigBase {

template <typename L> using EdgeFunctionPtrType = EdgeFunction<L>;

template <typename AnalysisDomainTy> using PathTrackingData = EmptyType;

template <typename ProblemTy>
static PathTrackingData<typename ProblemTy::ProblemAnalysisDomain>
initPathData(ProblemTy & /*Problem*/) {
return {};
}

template <typename AnalysisDomainTy>
static void saveEdges(PathTrackingData<AnalysisDomainTy> &Data,
ByConstRef<typename AnalysisDomainTy::n_t> Curr,
ByConstRef<typename AnalysisDomainTy::n_t> Succ,
ByConstRef<typename AnalysisDomainTy::d_t> CurrNode,
const auto &SuccNodes,
std::convertible_to<ESGEdgeKind> auto Kind) {}

static constexpr bool AutoAddZero = true;
static constexpr bool EnableStatistics = false;
static constexpr JumpFunctionGCMode EnableJumpFunctionGC =
Expand Down
5 changes: 5 additions & 0 deletions include/phasar/Utils/Lazy.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ template <typename Fn> struct lazy {
std::is_nothrow_invocable_v<Fn>) {
return std::invoke(std::move(F));
}

constexpr operator std::invoke_result_t<Fn>() & noexcept(
std::is_nothrow_invocable_v<Fn>) {
return std::invoke(F);
}
};

template <typename FF> lazy(FF) -> lazy<std::decay_t<FF>>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
if(PHASAR_USE_Z3)
add_phasar_unittest(PathTracingTest.cpp)
add_phasar_unittest(PathAwareIterIDESolverTest.cpp)

target_link_libraries(PathTracingTest
LINK_PUBLIC
Expand Down
Loading
Loading