Skip to content
Open
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions include/phasar/DataFlow/IfdsIde/EdgeFunctionStats.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <array>
Expand Down Expand Up @@ -72,7 +73,7 @@ class EdgeFunctionStats : public detail::EdgeFunctionStatsData {
const EdgeFunctionStats &S);

private:
template <typename AnalysisDomainTy, typename Container>
template <typename AnalysisDomainTy, typename Container, ICFG I>
friend class IDESolver;

constexpr EdgeFunctionStats(
Expand Down
74 changes: 32 additions & 42 deletions include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand All @@ -61,7 +61,6 @@
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_set>
#include <utility>

namespace psr {
Expand All @@ -70,10 +69,11 @@ namespace psr {
/// Sagiv, Horwitz and Reps. To solve the problem, call solve(). Results
/// can then be queried by using resultAt() and resultsAt().
template <typename AnalysisDomainTy,
typename Container = std::set<typename AnalysisDomainTy::d_t>>
typename Container = std::set<typename AnalysisDomainTy::d_t>,
ICFG ICFGTy = typename AnalysisDomainTy::i_t>
class IDESolver
: public IDESolverAPIMixin<IDESolver<AnalysisDomainTy, Container>> {
friend IDESolverAPIMixin<IDESolver<AnalysisDomainTy, Container>>;
: public IDESolverAPIMixin<IDESolver<AnalysisDomainTy, Container, ICFGTy>> {
friend IDESolverAPIMixin<IDESolver<AnalysisDomainTy, Container, ICFGTy>>;

public:
using ProblemTy = IDETabulationProblem<AnalysisDomainTy, Container>;
Expand All @@ -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 <std::convertible_to<const i_t &> I>
IDESolver(IDETabulationProblem<AnalysisDomainTy, Container> &Problem,
const I *ICF)
const ICFGTy *ICF)
: IDEProblem(Problem), ZeroValue(Problem.getZeroValue()),
ICF(&static_cast<const i_t &>(*ICF)), SVFG(ICF),
ICF(&assertNotNull(ICF)),
SolverConfig(Problem.getIFDSIDESolverConfig()),
CachedFlowEdgeFunctions(Problem), AllTop(Problem.allTopFunction()),
JumpFn(std::make_shared<JumpFunctions<AnalysisDomainTy, Container>>()),
Seeds(Problem.initialSeeds()) {
assert(ICF != nullptr);

if constexpr (has_getSparseCFG_v<I, d_t>) {
NextUserOrNullCB = &nextUserOrNullThunk<I>;
}
}
Seeds(Problem.initialSeeds()) {}

IDESolver(IDETabulationProblem<AnalysisDomainTy, Container> *Problem,
const i_t *ICF)
Expand Down Expand Up @@ -357,13 +350,19 @@ class IDESolver
}

protected:
Nullable<n_t> getNextUserOrNull(ByConstRef<f_t> Fun, ByConstRef<d_t> d3,
ByConstRef<n_t> n) {
if (!NextUserOrNullCB || IDEProblem.isZeroValue(d3)) {
[[nodiscard]] Nullable<n_t> getNextUserOrNull(ByConstRef<f_t> Fun,
ByConstRef<d_t> d3,
ByConstRef<n_t> n) {
if constexpr (has_getSparseCFG_v<ICFGTy, d_t>) {
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
Expand Down Expand Up @@ -1778,13 +1777,6 @@ class IDESolver
}

private:
template <typename I>
static auto nextUserOrNullThunk(const void *SVFG, ByConstRef<f_t> Fun,
ByConstRef<d_t> d3, ByConstRef<n_t> n) {
auto &&SCFG = static_cast<const I *>(SVFG)->getSparseCFG(Fun, d3);
return SCFG.nextUserOrNull(n);
};

/// @brief: Allows less-than comparison based on the statement ID.
struct StmtLess {
const i_t *ICF;
Expand Down Expand Up @@ -1881,10 +1873,7 @@ class IDESolver
IDETabulationProblem<AnalysisDomainTy, Container> &IDEProblem;
d_t ZeroValue;
const i_t *ICF;
const void *SVFG;
IFDSIDESolverConfig &SolverConfig;
Nullable<n_t> (*NextUserOrNullCB)(const void *, ByConstRef<f_t>,
ByConstRef<d_t>, ByConstRef<n_t>) = nullptr;

std::vector<std::pair<PathEdge<n_t, d_t>, EdgeFunction<l_t>>> WorkList;
std::vector<std::pair<n_t, d_t>> ValuePropWL;
Expand Down Expand Up @@ -1924,28 +1913,29 @@ class IDESolver
};

template <typename Problem, typename ICF>
IDESolver(Problem &, ICF *)
IDESolver(Problem &, const ICF *)
-> IDESolver<typename Problem::ProblemAnalysisDomain,
typename Problem::container_type>;
typename Problem::container_type, ICF>;

template <typename Problem, typename ICF>
IDESolver(Problem *, ICF *)
IDESolver(Problem *, const ICF *)
-> IDESolver<typename Problem::ProblemAnalysisDomain,
typename Problem::container_type>;
typename Problem::container_type, ICF>;

template <typename Problem>
using IDESolver_P = IDESolver<typename Problem::ProblemAnalysisDomain,
typename Problem::container_type>;
using IDESolver_P
[[deprecated("Let C++ deduce the template arguments of IDESolver, or call "
"solveIDEProblem() instead")]] =
IDESolver<typename Problem::ProblemAnalysisDomain,
typename Problem::container_type>;

template <typename AnalysisDomainTy, typename Container>
OwningSolverResults<typename AnalysisDomainTy::n_t,
typename AnalysisDomainTy::d_t,
typename AnalysisDomainTy::l_t>
solveIDEProblem(
IDETabulationProblem<AnalysisDomainTy, Container> &Problem,
const std::convertible_to<const typename AnalysisDomainTy::i_t &> auto
&ICF) {
IDESolver<AnalysisDomainTy, Container> Solver(&Problem, &ICF);
solveIDEProblem(IDETabulationProblem<AnalysisDomainTy, Container> &Problem,
const ICFG auto &ICF) {
IDESolver Solver(&Problem, &ICF);
Solver.solve();
return Solver.consumeSolverResults();
}
Expand Down
3 changes: 3 additions & 0 deletions include/phasar/DataFlow/IfdsIde/Solver/IDESolverAPIMixin.h
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,9 @@ template <typename Derived> class IDESolverAPIMixin {
}

private:
friend Derived;
constexpr IDESolverAPIMixin() noexcept = default;

[[nodiscard]] constexpr Derived &self() & noexcept {
static_assert(std::is_base_of_v<IDESolverAPIMixin, Derived>,
"Invalid CRTP instantiation");
Expand Down
53 changes: 30 additions & 23 deletions include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,26 +37,32 @@ namespace psr {
/// IFDSIDESolverConfig#setComputeValues(bool) to disable IDE's
/// phase 2.
template <typename AnalysisDomainTy,
typename Container = std::set<typename AnalysisDomainTy::d_t>>
class IFDSSolver
: public IDESolver<WithBinaryValueDomain<AnalysisDomainTy>, Container> {
typename Container = std::set<typename AnalysisDomainTy::d_t>,
ICFG ICFGTy = typename AnalysisDomainTy::i_t>
class IFDSSolver : public IDESolver<WithBinaryValueDomain<AnalysisDomainTy>,
Container, ICFGTy> {
using Base =
IDESolver<WithBinaryValueDomain<AnalysisDomainTy>, Container, ICFGTy>;

public:
using ProblemTy = IFDSTabulationProblem<AnalysisDomainTy>;
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 <std::derived_from<AnalysisDomainTy> IfdsDomainTy,
std::convertible_to<const i_t &> I>
template <typename IfdsDomainTy>
requires(std::same_as<WithBinaryValueDomain<AnalysisDomainTy>,
WithBinaryValueDomain<IfdsDomainTy>>)
IFDSSolver(IFDSTabulationProblem<IfdsDomainTy, Container> &IFDSProblem,
const I *ICF)
: IDESolver<WithBinaryValueDomain<AnalysisDomainTy>>(IFDSProblem, ICF) {}
const ICFGTy *ICF)
: Base(IFDSProblem, ICF) {}

template <std::derived_from<AnalysisDomainTy> IfdsDomainTy,
std::convertible_to<const i_t &> I>
template <typename IfdsDomainTy>
requires(std::same_as<WithBinaryValueDomain<AnalysisDomainTy>,
WithBinaryValueDomain<IfdsDomainTy>>)
IFDSSolver(IFDSTabulationProblem<IfdsDomainTy, Container> *IFDSProblem,
const I *ICF)
: IDESolver<WithBinaryValueDomain<AnalysisDomainTy>>(IFDSProblem, ICF) {}
const ICFGTy *ICF)
: Base(IFDSProblem, ICF) {}

~IFDSSolver() override = default;

Expand Down Expand Up @@ -110,26 +116,27 @@ class IFDSSolver
};

template <typename Problem, typename ICF>
IFDSSolver(Problem &, ICF *)
IFDSSolver(Problem &, const ICF *)
-> IFDSSolver<typename Problem::ProblemAnalysisDomain,
typename Problem::container_type>;
typename Problem::container_type, ICF>;
template <typename Problem, typename ICF>
IFDSSolver(Problem *, ICF *)
IFDSSolver(Problem *, const ICF *)
-> IFDSSolver<typename Problem::ProblemAnalysisDomain,
typename Problem::container_type>;
typename Problem::container_type, ICF>;

template <typename Problem>
using IFDSSolver_P = IFDSSolver<typename Problem::ProblemAnalysisDomain,
typename Problem::container_type>;
using IFDSSolver_P
[[deprecated("Let C++ deduce the template arguments of IFDSSolver, or call "
"solveIFDSProblem() instead")]] =
IFDSSolver<typename Problem::ProblemAnalysisDomain,
typename Problem::container_type>;

template <typename AnalysisDomainTy, typename Container>
OwningSolverResults<typename AnalysisDomainTy::n_t,
typename AnalysisDomainTy::d_t, BinaryDomain>
solveIFDSProblem(
IFDSTabulationProblem<AnalysisDomainTy, Container> &Problem,
const std::convertible_to<const typename AnalysisDomainTy::i_t &> auto
&ICF) {
IFDSSolver<AnalysisDomainTy, Container> Solver(Problem, &ICF);
solveIFDSProblem(IFDSTabulationProblem<AnalysisDomainTy, Container> &Problem,
const ICFG auto &ICF) {
IFDSSolver Solver(&Problem, &ICF);
Solver.solve();
return Solver.consumeSolverResults();
}
Expand Down
Loading
Loading