Skip to content

Commit

Permalink
Merge branch 'development' into f-SparseIDE
Browse files Browse the repository at this point in the history
  • Loading branch information
fabianbs96 committed Nov 28, 2024
2 parents dcb239d + 64a7233 commit 2335d4e
Show file tree
Hide file tree
Showing 122 changed files with 7,195 additions and 1,075 deletions.
3 changes: 2 additions & 1 deletion include/phasar/ControlFlow/CFGBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ template <typename Derived> class CFGBase {
void print(ByConstRef<f_t> Fun, llvm::raw_ostream &OS) const {
self().printImpl(Fun, OS);
}
[[nodiscard]] nlohmann::json getAsJson(ByConstRef<f_t> Fun) const {
[[nodiscard, deprecated("Please use printAsJson() instead")]] nlohmann::json
getAsJson(ByConstRef<f_t> Fun) const {
return self().getAsJsonImpl(Fun);
}

Expand Down
49 changes: 32 additions & 17 deletions include/phasar/ControlFlow/CallGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@
#define PHASAR_CONTROLFLOW_CALLGRAPH_H

#include "phasar/ControlFlow/CallGraphBase.h"
#include "phasar/ControlFlow/CallGraphData.h"
#include "phasar/Utils/ByRef.h"
#include "phasar/Utils/Logger.h"
#include "phasar/Utils/StableVector.h"
#include "phasar/Utils/Utilities.h"

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/Function.h"

#include "nlohmann/json.hpp"

#include <functional>
#include <string>
#include <utility>
#include <vector>

Expand Down Expand Up @@ -58,7 +58,7 @@ class CallGraph : public CallGraphBase<CallGraph<N, F>> {
/// Deserializes a previously computed call-graph
template <typename FunctionGetter, typename InstructionGetter>
[[nodiscard]] static CallGraph
deserialize(const nlohmann::json &PrecomputedCG,
deserialize(const CallGraphData &PrecomputedCG,
FunctionGetter GetFunctionFromName,
InstructionGetter GetInstructionFromId);

Expand Down Expand Up @@ -86,12 +86,33 @@ class CallGraph : public CallGraphBase<CallGraph<N, F>> {

[[nodiscard]] bool empty() const noexcept { return CallersOf.empty(); }

template <typename FunctionIdGetter, typename InstIdGetter>
void printAsJson(llvm::raw_ostream &OS, FunctionIdGetter GetFunctionId,
InstIdGetter GetInstructionId) const {
CallGraphData CGData;
CGData.FToFunctionVertexTy.reserve(CallersOf.size());

for (const auto &[Fun, Callers] : CallersOf) {
auto &JCallers =
CGData.FToFunctionVertexTy[std::invoke(GetFunctionId, Fun)];

CGData.FToFunctionVertexTy.reserve(Callers->size());
for (const auto &CS : *Callers) {
JCallers.push_back(std::invoke(GetInstructionId, CS));
}
}

CGData.printAsJson(OS);
}

/// Creates a JSON representation of this call-graph suitable for presistent
/// storage.
/// Use the ctor taking a json object for deserialization
template <typename FunctionIdGetter, typename InstIdGetter>
[[nodiscard]] nlohmann::json getAsJson(FunctionIdGetter GetFunctionId,
InstIdGetter GetInstructionId) const {
[[nodiscard]] [[deprecated(
"Please use printAsJson() instead")]] nlohmann::json
getAsJson(FunctionIdGetter GetFunctionId,
InstIdGetter GetInstructionId) const {
nlohmann::json J;

for (const auto &[Fun, Callers] : CallersOf) {
Expand Down Expand Up @@ -254,18 +275,13 @@ template <typename N, typename F> class CallGraphBuilder {
template <typename N, typename F>
template <typename FunctionGetter, typename InstructionGetter>
[[nodiscard]] CallGraph<N, F>
CallGraph<N, F>::deserialize(const nlohmann::json &PrecomputedCG,
CallGraph<N, F>::deserialize(const CallGraphData &PrecomputedCG,
FunctionGetter GetFunctionFromName,
InstructionGetter GetInstructionFromId) {
if (!PrecomputedCG.is_object()) {
PHASAR_LOG_LEVEL_CAT(ERROR, "CallGraph", "Invalid Json. Expected object");
return {};
}

CallGraphBuilder<N, F> CGBuilder;
CGBuilder.reserve(PrecomputedCG.size());
CGBuilder.reserve(PrecomputedCG.FToFunctionVertexTy.size());

for (const auto &[FunName, CallerIDs] : PrecomputedCG.items()) {
for (const auto &[FunName, CallerIDs] : PrecomputedCG.FToFunctionVertexTy) {
const auto &Fun = std::invoke(GetFunctionFromName, FunName);
if (!Fun) {
PHASAR_LOG_LEVEL_CAT(WARNING, "CallGraph",
Expand All @@ -277,11 +293,10 @@ CallGraph<N, F>::deserialize(const nlohmann::json &PrecomputedCG,
CEdges->reserve(CallerIDs.size());

for (const auto &JId : CallerIDs) {
auto Id = JId.get<size_t>();
const auto &CS = std::invoke(GetInstructionFromId, Id);
const auto &CS = std::invoke(GetInstructionFromId, JId);
if (!CS) {
PHASAR_LOG_LEVEL_CAT(WARNING, "CallGraph",
"Invalid CAll-Instruction Id: " << Id);
"Invalid Call-Instruction Id: " << JId);
}

CGBuilder.addCallEdge(CS, Fun);
Expand Down
34 changes: 34 additions & 0 deletions include/phasar/ControlFlow/CallGraphData.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/******************************************************************************
* Copyright (c) 2024 Fabian Schiebel.
* All rights reserved. This program and the accompanying materials are made
* available under the terms of LICENSE.txt.
*
* Contributors:
* Maximilian Leo Huber and others
*****************************************************************************/

#ifndef PHASAR_PHASARLLVM_CONTROLFLOW_CALLGRAPHDATA_H
#define PHASAR_PHASARLLVM_CONTROLFLOW_CALLGRAPHDATA_H

#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"

#include <string>
#include <unordered_map>
#include <vector>

namespace psr {
struct CallGraphData {
// Mangled FunName --> [CS-IDs]
std::unordered_map<std::string, std::vector<uint32_t>> FToFunctionVertexTy{};

CallGraphData() noexcept = default;
void printAsJson(llvm::raw_ostream &OS);

static CallGraphData deserializeJson(const llvm::Twine &Path);
static CallGraphData loadJsonString(llvm::StringRef JsonAsString);
};

} // namespace psr

#endif // PHASAR_PHASARLLVM_CONTROLFLOW_CALLGRAPHDATA_H
14 changes: 13 additions & 1 deletion include/phasar/ControlFlow/ICFGBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,23 @@ template <typename Derived> class ICFGBase {
void print(llvm::raw_ostream &OS = llvm::outs()) const {
self().printImpl(OS);
}

/// Prints the underlying call-graph as Json to the given output-stream
void printAsJson(llvm::raw_ostream &OS = llvm::outs()) const {
self().printAsJsonImpl(OS);
}

/// Returns the underlying call-graph as JSON
[[nodiscard]] nlohmann::json getAsJson() const {
[[nodiscard]] [[deprecated(
"Please use printAsJson() instead")]] nlohmann::json
getAsJson() const {
return self().getAsJsonImpl();
}

[[nodiscard]] size_t getNumCallSites() const noexcept {
return self().getNumCallSitesImpl();
}

private:
const Derived &self() const noexcept {
return static_cast<const Derived &>(*this);
Expand Down
1 change: 1 addition & 0 deletions include/phasar/DataFlow/IfdsIde/EdgeFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "phasar/DataFlow/IfdsIde/EdgeFunctionSingletonCache.h"
#include "phasar/Utils/ByRef.h"
#include "phasar/Utils/EmptyBaseOptimizationUtils.h"
#include "phasar/Utils/TypeTraits.h"

#include "llvm/ADT/DenseMapInfo.h"
Expand Down
108 changes: 108 additions & 0 deletions include/phasar/DataFlow/IfdsIde/GenericFlowFunction.h
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
7 changes: 5 additions & 2 deletions include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "phasar/DataFlow/IfdsIde/FlowFunctions.h"
#include "phasar/DataFlow/IfdsIde/IFDSIDESolverConfig.h"
#include "phasar/DataFlow/IfdsIde/InitialSeeds.h"
#include "phasar/DataFlow/IfdsIde/Solver/GenericSolverResults.h"
#include "phasar/DataFlow/IfdsIde/SolverResults.h"
#include "phasar/Utils/JoinLattice.h"
#include "phasar/Utils/NullAnalysisPrinter.h"
Expand Down Expand Up @@ -134,15 +135,15 @@ class IDETabulationProblem : public FlowFunctions<AnalysisDomainTy, Container>,
/// Generates a text report of the results that is written to the specified
/// output stream.
virtual void
emitTextReport([[maybe_unused]] const SolverResults<n_t, d_t, l_t> &Results,
emitTextReport([[maybe_unused]] GenericSolverResults<n_t, d_t, l_t> Results,
llvm::raw_ostream &OS = llvm::outs()) {
OS << "No text report available!\n";
}

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

const ProjectIRDBBase<db_t> *getProjectIRDB() const noexcept { return IRDB; }

protected:
typename FlowFunctions<AnalysisDomainTy, Container>::FlowFunctionPtrType
generateFromZero(d_t FactToGenerate) {
Expand Down
Loading

0 comments on commit 2335d4e

Please sign in to comment.