Skip to content

Commit aae2109

Browse files
committed
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"
1 parent 6e0f6f6 commit aae2109

File tree

65 files changed

+5372
-401
lines changed

Some content is hidden

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

65 files changed

+5372
-401
lines changed

include/phasar/ControlFlow/ICFGBase.h

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

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

0 commit comments

Comments
 (0)