-
Notifications
You must be signed in to change notification settings - Fork 142
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
1 parent
96f0758
commit 64a7233
Showing
66 changed files
with
5,182 additions
and
409 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_GENERICFLOWFUNCTION_H | ||
#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_GENERICFLOWFUNCTION_H | ||
|
||
#include "phasar/DataFlow/IfdsIde/FlowFunctions.h" | ||
|
||
namespace psr { | ||
/// Encapsulates an unmanaged pointer to a FlowFunction | ||
template <typename D, typename Container = std::set<D>> | ||
class GenericFlowFunctionView { | ||
public: | ||
using FlowFunctionType = FlowFunction<D, Container>; | ||
using FlowFunctionPtrType = std::unique_ptr<FlowFunctionType>; | ||
|
||
using container_type = Container; | ||
using value_type = typename container_type::value_type; | ||
|
||
GenericFlowFunctionView() noexcept = default; | ||
GenericFlowFunctionView(FlowFunctionType *FF) noexcept : FF(FF) {} | ||
|
||
GenericFlowFunctionView(const GenericFlowFunctionView &) noexcept = default; | ||
GenericFlowFunctionView & | ||
operator=(const GenericFlowFunctionView &) noexcept = default; | ||
|
||
~GenericFlowFunctionView() = default; | ||
|
||
[[nodiscard]] container_type computeTargets(D Source) const { | ||
assert(FF != nullptr); | ||
return FF->computeTargets(std::move(Source)); | ||
} | ||
|
||
explicit operator bool() const noexcept { return FF; } | ||
|
||
[[nodiscard]] bool operator==(GenericFlowFunctionView Other) const noexcept { | ||
return FF == Other.FF; | ||
} | ||
[[nodiscard]] bool operator==(std::nullptr_t) const noexcept { | ||
return FF == nullptr; | ||
} | ||
[[nodiscard]] bool operator!=(GenericFlowFunctionView Other) const noexcept { | ||
return !(*this == Other); | ||
} | ||
[[nodiscard]] bool operator!=(std::nullptr_t) const noexcept { return FF; } | ||
|
||
private: | ||
FlowFunctionType *FF = nullptr; | ||
}; | ||
|
||
/// Encapsulates a managed pointer to a FlowFunction | ||
template <typename D, typename Container = std::set<D>> | ||
class GenericFlowFunction { | ||
public: | ||
using FlowFunctionType = FlowFunction<D, Container>; | ||
using FlowFunctionPtrType = typename FlowFunctionType::FlowFunctionPtrType; | ||
|
||
using container_type = Container; | ||
using value_type = typename container_type::value_type; | ||
|
||
GenericFlowFunction() noexcept = default; | ||
GenericFlowFunction(FlowFunctionPtrType FF) noexcept : FF(std::move(FF)) {} | ||
template <typename T, typename = std::enable_if_t<std::is_base_of_v< | ||
FlowFunctionType, std::decay_t<T>>>> | ||
GenericFlowFunction(T &&FF) | ||
: FF(std::make_unique<std::decay_t<T>>(std::forward<T>(FF))) {} | ||
|
||
template <typename T, typename... ArgTys> | ||
explicit GenericFlowFunction(std::in_place_type_t<T> /*unused*/, | ||
ArgTys &&...Args) | ||
: FF(std::make_unique<T>(std::forward<ArgTys>(Args)...)) {} | ||
|
||
GenericFlowFunction(GenericFlowFunction &&) noexcept = default; | ||
GenericFlowFunction &operator=(GenericFlowFunction &&) noexcept = default; | ||
|
||
GenericFlowFunction(const GenericFlowFunction &) = delete; | ||
GenericFlowFunction &operator=(const GenericFlowFunction &) = delete; | ||
|
||
~GenericFlowFunction() = default; | ||
|
||
[[nodiscard]] container_type computeTargets(D Source) const { | ||
assert(FF != nullptr); | ||
return FF->computeTargets(std::move(Source)); | ||
} | ||
|
||
explicit operator bool() const noexcept { return FF; } | ||
|
||
operator GenericFlowFunctionView<D, Container>() const noexcept { | ||
return FF.get(); | ||
} | ||
|
||
[[nodiscard]] bool | ||
operator==(GenericFlowFunctionView<D, Container> Other) const noexcept { | ||
return FF == Other.FF; | ||
} | ||
[[nodiscard]] bool operator==(std::nullptr_t) const noexcept { | ||
return FF == nullptr; | ||
} | ||
[[nodiscard]] bool | ||
operator!=(GenericFlowFunctionView<D, Container> Other) const noexcept { | ||
return !(*this == Other); | ||
} | ||
[[nodiscard]] bool operator!=(std::nullptr_t) const noexcept { return FF; } | ||
|
||
private: | ||
FlowFunctionPtrType FF; | ||
}; | ||
|
||
} // namespace psr | ||
|
||
#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_GENERICFLOWFUNCTION_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
#ifndef PHASAR_DATAFLOW_IFDSIDE_SOLVER_COMPRESSOR_H | ||
#define PHASAR_DATAFLOW_IFDSIDE_SOLVER_COMPRESSOR_H | ||
|
||
#include "phasar/DB/ProjectIRDBBase.h" | ||
#include "phasar/Utils/ByRef.h" | ||
#include "phasar/Utils/TypeTraits.h" | ||
|
||
#include "llvm/ADT/DenseMap.h" | ||
#include "llvm/ADT/DenseMapInfo.h" | ||
#include "llvm/ADT/SmallVector.h" | ||
|
||
#include <cstdint> | ||
#include <deque> | ||
#include <functional> | ||
#include <optional> | ||
#include <type_traits> | ||
|
||
namespace psr { | ||
template <typename T, typename Enable = void> class Compressor; | ||
|
||
template <typename T> | ||
class Compressor<T, std::enable_if_t<CanEfficientlyPassByValue<T>>> { | ||
public: | ||
void reserve(size_t Capacity) { | ||
assert(Capacity <= UINT32_MAX); | ||
ToInt.reserve(Capacity); | ||
FromInt.reserve(Capacity); | ||
} | ||
|
||
uint32_t getOrInsert(T Elem) { | ||
auto [It, Inserted] = ToInt.try_emplace(Elem, ToInt.size()); | ||
if (Inserted) { | ||
FromInt.push_back(Elem); | ||
} | ||
return It->second; | ||
} | ||
|
||
std::optional<uint32_t> getOrNull(T Elem) const { | ||
if (auto It = ToInt.find(Elem); It != ToInt.end()) { | ||
return It->second; | ||
} | ||
return std::nullopt; | ||
} | ||
|
||
T operator[](size_t Idx) const noexcept { | ||
assert(Idx < FromInt.size()); | ||
return FromInt[Idx]; | ||
} | ||
|
||
[[nodiscard]] size_t size() const noexcept { return FromInt.size(); } | ||
[[nodiscard]] size_t capacity() const noexcept { | ||
return FromInt.capacity() + | ||
ToInt.getMemorySize() / sizeof(typename decltype(ToInt)::value_type); | ||
} | ||
|
||
auto begin() const noexcept { return FromInt.begin(); } | ||
auto end() const noexcept { return FromInt.end(); } | ||
|
||
private: | ||
llvm::DenseMap<T, uint32_t> ToInt; | ||
llvm::SmallVector<T, 0> FromInt; | ||
}; | ||
|
||
template <typename T> | ||
class Compressor<T, std::enable_if_t<!CanEfficientlyPassByValue<T>>> { | ||
public: | ||
void reserve(size_t Capacity) { | ||
assert(Capacity <= UINT32_MAX); | ||
ToInt.reserve(Capacity); | ||
} | ||
|
||
uint32_t getOrInsert(const T &Elem) { | ||
if (auto It = ToInt.find(&Elem); It != ToInt.end()) { | ||
return It->second; | ||
} | ||
auto Ret = FromInt.size(); | ||
auto *Ins = &FromInt.emplace_back(Elem); | ||
ToInt[Ins] = Ret; | ||
return Ret; | ||
} | ||
|
||
uint32_t getOrInsert(T &&Elem) { | ||
if (auto It = ToInt.find(&Elem); It != ToInt.end()) { | ||
return It->second; | ||
} | ||
auto Ret = FromInt.size(); | ||
auto *Ins = &FromInt.emplace_back(std::move(Elem)); | ||
ToInt[Ins] = Ret; | ||
return Ret; | ||
} | ||
|
||
std::optional<uint32_t> getOrNull(const T &Elem) const { | ||
if (auto It = ToInt.find(&Elem); It != ToInt.end()) { | ||
return It->second; | ||
} | ||
return std::nullopt; | ||
} | ||
|
||
const T &operator[](size_t Idx) const noexcept { | ||
assert(Idx < FromInt.size()); | ||
return FromInt[Idx]; | ||
} | ||
|
||
[[nodiscard]] size_t size() const noexcept { return FromInt.size(); } | ||
[[nodiscard]] size_t capacity() const noexcept { | ||
return FromInt.size() + | ||
ToInt.getMemorySize() / sizeof(typename decltype(ToInt)::value_type); | ||
} | ||
|
||
auto begin() const noexcept { return FromInt.begin(); } | ||
auto end() const noexcept { return FromInt.end(); } | ||
|
||
private: | ||
struct DSI : llvm::DenseMapInfo<const T *> { | ||
static auto getHashValue(const T *Elem) noexcept { | ||
assert(Elem != nullptr); | ||
if constexpr (has_llvm_dense_map_info<T>) { | ||
return llvm::DenseMapInfo<T>::getHashValue(*Elem); | ||
} else { | ||
return std::hash<T>{}(*Elem); | ||
} | ||
} | ||
static auto isEqual(const T *LHS, const T *RHS) noexcept { | ||
if (LHS == RHS) { | ||
return true; | ||
} | ||
if (LHS == DSI::getEmptyKey() || LHS == DSI::getTombstoneKey() || | ||
RHS == DSI::getEmptyKey() || RHS == DSI::getTombstoneKey()) { | ||
return false; | ||
} | ||
if constexpr (has_llvm_dense_map_info<T>) { | ||
return llvm::DenseMapInfo<T>::isEqual(*LHS, *RHS); | ||
} else { | ||
return *LHS == *RHS; | ||
} | ||
} | ||
}; | ||
|
||
std::deque<T> FromInt; | ||
llvm::DenseMap<const T *, uint32_t, DSI> ToInt; | ||
}; | ||
|
||
struct NoneCompressor final { | ||
constexpr NoneCompressor() noexcept = default; | ||
|
||
template <typename T, | ||
typename = std::enable_if_t<!std::is_same_v<NoneCompressor, T>>> | ||
constexpr NoneCompressor(const T & /*unused*/) noexcept {} | ||
|
||
template <typename T> | ||
[[nodiscard]] decltype(auto) getOrInsert(T &&Val) const noexcept { | ||
return std::forward<T>(Val); | ||
} | ||
template <typename T> | ||
[[nodiscard]] decltype(auto) operator[](T &&Val) const noexcept { | ||
return std::forward<T>(Val); | ||
} | ||
void reserve(size_t /*unused*/) const noexcept {} | ||
|
||
[[nodiscard]] size_t size() const noexcept { return 0; } | ||
[[nodiscard]] size_t capacity() const noexcept { return 0; } | ||
}; | ||
|
||
class LLVMProjectIRDB; | ||
|
||
/// Once we have fast instruction IDs (as we already have in IntelliSecPhasar), | ||
/// we might want to create a specialization for T/const llvm::Value * that uses | ||
/// the IDs from the IRDB | ||
template <typename T> struct NodeCompressorTraits { | ||
using type = Compressor<T>; | ||
|
||
static type create(const ProjectIRDBBase<LLVMProjectIRDB> | ||
* /*IRDB*/) noexcept(noexcept(type())) { | ||
return type(); | ||
} | ||
}; | ||
|
||
template <typename T, typename = void> struct ValCompressorTraits { | ||
using type = Compressor<T>; | ||
using id_type = uint32_t; | ||
}; | ||
|
||
template <typename T> | ||
struct ValCompressorTraits<T, std::enable_if_t<CanEfficientlyPassByValue<T>>> { | ||
using type = NoneCompressor; | ||
using id_type = T; | ||
}; | ||
|
||
} // namespace psr | ||
|
||
#endif // PHASAR_DATAFLOW_IFDSIDE_SOLVER_COMPRESSOR_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.