Skip to content

Commit 64a7233

Browse files
authored
Pull in the IDESolver++ (aka. IterativeIDESolver) (#733)
* Pull in the IDESolver++ (aka. IterativeIDESolver) The solver is set-up in JF_N configuration from the paper "Scaling Interprocedural Static Data-Flow Analysis to Large C/C++ Applications: An Experience Report" * Some cleanup based on review * edge fact printing * more cleanup * tracking issue for c++20 * minor cleanup * Add alignment comment * Apply review comments * Remove confusing copyright notes + fix header guards for newly added files
1 parent 96f0758 commit 64a7233

File tree

66 files changed

+5182
-409
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+5182
-409
lines changed

include/phasar/ControlFlow/ICFGBase.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ template <typename Derived> class ICFGBase {
119119
return self().getAsJsonImpl();
120120
}
121121

122+
[[nodiscard]] size_t getNumCallSites() const noexcept {
123+
return self().getNumCallSitesImpl();
124+
}
125+
122126
private:
123127
const Derived &self() const noexcept {
124128
return static_cast<const Derived &>(*this);

include/phasar/DataFlow/IfdsIde/EdgeFunction.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "phasar/DataFlow/IfdsIde/EdgeFunctionSingletonCache.h"
1414
#include "phasar/Utils/ByRef.h"
15+
#include "phasar/Utils/EmptyBaseOptimizationUtils.h"
1516
#include "phasar/Utils/TypeTraits.h"
1617

1718
#include "llvm/ADT/DenseMapInfo.h"
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_GENERICFLOWFUNCTION_H
2+
#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_GENERICFLOWFUNCTION_H
3+
4+
#include "phasar/DataFlow/IfdsIde/FlowFunctions.h"
5+
6+
namespace psr {
7+
/// Encapsulates an unmanaged pointer to a FlowFunction
8+
template <typename D, typename Container = std::set<D>>
9+
class GenericFlowFunctionView {
10+
public:
11+
using FlowFunctionType = FlowFunction<D, Container>;
12+
using FlowFunctionPtrType = std::unique_ptr<FlowFunctionType>;
13+
14+
using container_type = Container;
15+
using value_type = typename container_type::value_type;
16+
17+
GenericFlowFunctionView() noexcept = default;
18+
GenericFlowFunctionView(FlowFunctionType *FF) noexcept : FF(FF) {}
19+
20+
GenericFlowFunctionView(const GenericFlowFunctionView &) noexcept = default;
21+
GenericFlowFunctionView &
22+
operator=(const GenericFlowFunctionView &) noexcept = default;
23+
24+
~GenericFlowFunctionView() = default;
25+
26+
[[nodiscard]] container_type computeTargets(D Source) const {
27+
assert(FF != nullptr);
28+
return FF->computeTargets(std::move(Source));
29+
}
30+
31+
explicit operator bool() const noexcept { return FF; }
32+
33+
[[nodiscard]] bool operator==(GenericFlowFunctionView Other) const noexcept {
34+
return FF == Other.FF;
35+
}
36+
[[nodiscard]] bool operator==(std::nullptr_t) const noexcept {
37+
return FF == nullptr;
38+
}
39+
[[nodiscard]] bool operator!=(GenericFlowFunctionView Other) const noexcept {
40+
return !(*this == Other);
41+
}
42+
[[nodiscard]] bool operator!=(std::nullptr_t) const noexcept { return FF; }
43+
44+
private:
45+
FlowFunctionType *FF = nullptr;
46+
};
47+
48+
/// Encapsulates a managed pointer to a FlowFunction
49+
template <typename D, typename Container = std::set<D>>
50+
class GenericFlowFunction {
51+
public:
52+
using FlowFunctionType = FlowFunction<D, Container>;
53+
using FlowFunctionPtrType = typename FlowFunctionType::FlowFunctionPtrType;
54+
55+
using container_type = Container;
56+
using value_type = typename container_type::value_type;
57+
58+
GenericFlowFunction() noexcept = default;
59+
GenericFlowFunction(FlowFunctionPtrType FF) noexcept : FF(std::move(FF)) {}
60+
template <typename T, typename = std::enable_if_t<std::is_base_of_v<
61+
FlowFunctionType, std::decay_t<T>>>>
62+
GenericFlowFunction(T &&FF)
63+
: FF(std::make_unique<std::decay_t<T>>(std::forward<T>(FF))) {}
64+
65+
template <typename T, typename... ArgTys>
66+
explicit GenericFlowFunction(std::in_place_type_t<T> /*unused*/,
67+
ArgTys &&...Args)
68+
: FF(std::make_unique<T>(std::forward<ArgTys>(Args)...)) {}
69+
70+
GenericFlowFunction(GenericFlowFunction &&) noexcept = default;
71+
GenericFlowFunction &operator=(GenericFlowFunction &&) noexcept = default;
72+
73+
GenericFlowFunction(const GenericFlowFunction &) = delete;
74+
GenericFlowFunction &operator=(const GenericFlowFunction &) = delete;
75+
76+
~GenericFlowFunction() = default;
77+
78+
[[nodiscard]] container_type computeTargets(D Source) const {
79+
assert(FF != nullptr);
80+
return FF->computeTargets(std::move(Source));
81+
}
82+
83+
explicit operator bool() const noexcept { return FF; }
84+
85+
operator GenericFlowFunctionView<D, Container>() const noexcept {
86+
return FF.get();
87+
}
88+
89+
[[nodiscard]] bool
90+
operator==(GenericFlowFunctionView<D, Container> Other) const noexcept {
91+
return FF == Other.FF;
92+
}
93+
[[nodiscard]] bool operator==(std::nullptr_t) const noexcept {
94+
return FF == nullptr;
95+
}
96+
[[nodiscard]] bool
97+
operator!=(GenericFlowFunctionView<D, Container> Other) const noexcept {
98+
return !(*this == Other);
99+
}
100+
[[nodiscard]] bool operator!=(std::nullptr_t) const noexcept { return FF; }
101+
102+
private:
103+
FlowFunctionPtrType FF;
104+
};
105+
106+
} // namespace psr
107+
108+
#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_GENERICFLOWFUNCTION_H

include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "phasar/DataFlow/IfdsIde/FlowFunctions.h"
1919
#include "phasar/DataFlow/IfdsIde/IFDSIDESolverConfig.h"
2020
#include "phasar/DataFlow/IfdsIde/InitialSeeds.h"
21+
#include "phasar/DataFlow/IfdsIde/Solver/GenericSolverResults.h"
2122
#include "phasar/DataFlow/IfdsIde/SolverResults.h"
2223
#include "phasar/Utils/JoinLattice.h"
2324
#include "phasar/Utils/NullAnalysisPrinter.h"
@@ -134,15 +135,15 @@ class IDETabulationProblem : public FlowFunctions<AnalysisDomainTy, Container>,
134135
/// Generates a text report of the results that is written to the specified
135136
/// output stream.
136137
virtual void
137-
emitTextReport([[maybe_unused]] const SolverResults<n_t, d_t, l_t> &Results,
138+
emitTextReport([[maybe_unused]] GenericSolverResults<n_t, d_t, l_t> Results,
138139
llvm::raw_ostream &OS = llvm::outs()) {
139140
OS << "No text report available!\n";
140141
}
141142

142143
/// Generates a graphical report, e.g. in html or other markup languages, of
143144
/// the results that is written to the specified output stream.
144145
virtual void emitGraphicalReport(
145-
[[maybe_unused]] const SolverResults<n_t, d_t, l_t> &Results,
146+
[[maybe_unused]] GenericSolverResults<n_t, d_t, l_t> Results,
146147
llvm::raw_ostream &OS = llvm::outs()) {
147148
OS << "No graphical report available!\n";
148149
}
@@ -151,6 +152,8 @@ class IDETabulationProblem : public FlowFunctions<AnalysisDomainTy, Container>,
151152
/// the level of soundness is ignored. Otherwise, true.
152153
virtual bool setSoundness(Soundness /*S*/) { return false; }
153154

155+
const ProjectIRDBBase<db_t> *getProjectIRDB() const noexcept { return IRDB; }
156+
154157
protected:
155158
typename FlowFunctions<AnalysisDomainTy, Container>::FlowFunctionPtrType
156159
generateFromZero(d_t FactToGenerate) {
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
#ifndef PHASAR_DATAFLOW_IFDSIDE_SOLVER_COMPRESSOR_H
2+
#define PHASAR_DATAFLOW_IFDSIDE_SOLVER_COMPRESSOR_H
3+
4+
#include "phasar/DB/ProjectIRDBBase.h"
5+
#include "phasar/Utils/ByRef.h"
6+
#include "phasar/Utils/TypeTraits.h"
7+
8+
#include "llvm/ADT/DenseMap.h"
9+
#include "llvm/ADT/DenseMapInfo.h"
10+
#include "llvm/ADT/SmallVector.h"
11+
12+
#include <cstdint>
13+
#include <deque>
14+
#include <functional>
15+
#include <optional>
16+
#include <type_traits>
17+
18+
namespace psr {
19+
template <typename T, typename Enable = void> class Compressor;
20+
21+
template <typename T>
22+
class Compressor<T, std::enable_if_t<CanEfficientlyPassByValue<T>>> {
23+
public:
24+
void reserve(size_t Capacity) {
25+
assert(Capacity <= UINT32_MAX);
26+
ToInt.reserve(Capacity);
27+
FromInt.reserve(Capacity);
28+
}
29+
30+
uint32_t getOrInsert(T Elem) {
31+
auto [It, Inserted] = ToInt.try_emplace(Elem, ToInt.size());
32+
if (Inserted) {
33+
FromInt.push_back(Elem);
34+
}
35+
return It->second;
36+
}
37+
38+
std::optional<uint32_t> getOrNull(T Elem) const {
39+
if (auto It = ToInt.find(Elem); It != ToInt.end()) {
40+
return It->second;
41+
}
42+
return std::nullopt;
43+
}
44+
45+
T operator[](size_t Idx) const noexcept {
46+
assert(Idx < FromInt.size());
47+
return FromInt[Idx];
48+
}
49+
50+
[[nodiscard]] size_t size() const noexcept { return FromInt.size(); }
51+
[[nodiscard]] size_t capacity() const noexcept {
52+
return FromInt.capacity() +
53+
ToInt.getMemorySize() / sizeof(typename decltype(ToInt)::value_type);
54+
}
55+
56+
auto begin() const noexcept { return FromInt.begin(); }
57+
auto end() const noexcept { return FromInt.end(); }
58+
59+
private:
60+
llvm::DenseMap<T, uint32_t> ToInt;
61+
llvm::SmallVector<T, 0> FromInt;
62+
};
63+
64+
template <typename T>
65+
class Compressor<T, std::enable_if_t<!CanEfficientlyPassByValue<T>>> {
66+
public:
67+
void reserve(size_t Capacity) {
68+
assert(Capacity <= UINT32_MAX);
69+
ToInt.reserve(Capacity);
70+
}
71+
72+
uint32_t getOrInsert(const T &Elem) {
73+
if (auto It = ToInt.find(&Elem); It != ToInt.end()) {
74+
return It->second;
75+
}
76+
auto Ret = FromInt.size();
77+
auto *Ins = &FromInt.emplace_back(Elem);
78+
ToInt[Ins] = Ret;
79+
return Ret;
80+
}
81+
82+
uint32_t getOrInsert(T &&Elem) {
83+
if (auto It = ToInt.find(&Elem); It != ToInt.end()) {
84+
return It->second;
85+
}
86+
auto Ret = FromInt.size();
87+
auto *Ins = &FromInt.emplace_back(std::move(Elem));
88+
ToInt[Ins] = Ret;
89+
return Ret;
90+
}
91+
92+
std::optional<uint32_t> getOrNull(const T &Elem) const {
93+
if (auto It = ToInt.find(&Elem); It != ToInt.end()) {
94+
return It->second;
95+
}
96+
return std::nullopt;
97+
}
98+
99+
const T &operator[](size_t Idx) const noexcept {
100+
assert(Idx < FromInt.size());
101+
return FromInt[Idx];
102+
}
103+
104+
[[nodiscard]] size_t size() const noexcept { return FromInt.size(); }
105+
[[nodiscard]] size_t capacity() const noexcept {
106+
return FromInt.size() +
107+
ToInt.getMemorySize() / sizeof(typename decltype(ToInt)::value_type);
108+
}
109+
110+
auto begin() const noexcept { return FromInt.begin(); }
111+
auto end() const noexcept { return FromInt.end(); }
112+
113+
private:
114+
struct DSI : llvm::DenseMapInfo<const T *> {
115+
static auto getHashValue(const T *Elem) noexcept {
116+
assert(Elem != nullptr);
117+
if constexpr (has_llvm_dense_map_info<T>) {
118+
return llvm::DenseMapInfo<T>::getHashValue(*Elem);
119+
} else {
120+
return std::hash<T>{}(*Elem);
121+
}
122+
}
123+
static auto isEqual(const T *LHS, const T *RHS) noexcept {
124+
if (LHS == RHS) {
125+
return true;
126+
}
127+
if (LHS == DSI::getEmptyKey() || LHS == DSI::getTombstoneKey() ||
128+
RHS == DSI::getEmptyKey() || RHS == DSI::getTombstoneKey()) {
129+
return false;
130+
}
131+
if constexpr (has_llvm_dense_map_info<T>) {
132+
return llvm::DenseMapInfo<T>::isEqual(*LHS, *RHS);
133+
} else {
134+
return *LHS == *RHS;
135+
}
136+
}
137+
};
138+
139+
std::deque<T> FromInt;
140+
llvm::DenseMap<const T *, uint32_t, DSI> ToInt;
141+
};
142+
143+
struct NoneCompressor final {
144+
constexpr NoneCompressor() noexcept = default;
145+
146+
template <typename T,
147+
typename = std::enable_if_t<!std::is_same_v<NoneCompressor, T>>>
148+
constexpr NoneCompressor(const T & /*unused*/) noexcept {}
149+
150+
template <typename T>
151+
[[nodiscard]] decltype(auto) getOrInsert(T &&Val) const noexcept {
152+
return std::forward<T>(Val);
153+
}
154+
template <typename T>
155+
[[nodiscard]] decltype(auto) operator[](T &&Val) const noexcept {
156+
return std::forward<T>(Val);
157+
}
158+
void reserve(size_t /*unused*/) const noexcept {}
159+
160+
[[nodiscard]] size_t size() const noexcept { return 0; }
161+
[[nodiscard]] size_t capacity() const noexcept { return 0; }
162+
};
163+
164+
class LLVMProjectIRDB;
165+
166+
/// Once we have fast instruction IDs (as we already have in IntelliSecPhasar),
167+
/// we might want to create a specialization for T/const llvm::Value * that uses
168+
/// the IDs from the IRDB
169+
template <typename T> struct NodeCompressorTraits {
170+
using type = Compressor<T>;
171+
172+
static type create(const ProjectIRDBBase<LLVMProjectIRDB>
173+
* /*IRDB*/) noexcept(noexcept(type())) {
174+
return type();
175+
}
176+
};
177+
178+
template <typename T, typename = void> struct ValCompressorTraits {
179+
using type = Compressor<T>;
180+
using id_type = uint32_t;
181+
};
182+
183+
template <typename T>
184+
struct ValCompressorTraits<T, std::enable_if_t<CanEfficientlyPassByValue<T>>> {
185+
using type = NoneCompressor;
186+
using id_type = T;
187+
};
188+
189+
} // namespace psr
190+
191+
#endif // PHASAR_DATAFLOW_IFDSIDE_SOLVER_COMPRESSOR_H

include/phasar/DataFlow/IfdsIde/Solver/ESGEdgeKind.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#ifndef PHASAR_DATAFLOW_IFDSIDE_SOLVER_ESGEDGEKIND_H
2+
#define PHASAR_DATAFLOW_IFDSIDE_SOLVER_ESGEDGEKIND_H
3+
14
/******************************************************************************
25
* Copyright (c) 2022 Philipp Schubert.
36
* All rights reserved. This program and the accompanying materials are made
@@ -7,9 +10,6 @@
710
* Fabian Schiebel and others
811
*****************************************************************************/
912

10-
#ifndef PHASAR_DATAFLOW_IFDSIDE_SOLVER_ESGEDGEKIND_H
11-
#define PHASAR_DATAFLOW_IFDSIDE_SOLVER_ESGEDGEKIND_H
12-
1313
namespace psr {
1414
enum class ESGEdgeKind { Normal, Call, CallToRet, SkipUnknownFn, Ret, Summary };
1515

0 commit comments

Comments
 (0)