From 8666f7845d6410783e970b0be8a5fe85257535d6 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 21 Apr 2023 10:21:59 +0200 Subject: [PATCH 01/14] Fix some bugs --- include/phasar/DB/ProjectIRDBBase.h | 2 +- include/phasar/Utils/MaybeUniquePtr.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/phasar/DB/ProjectIRDBBase.h b/include/phasar/DB/ProjectIRDBBase.h index 78c946417a..092019686d 100644 --- a/include/phasar/DB/ProjectIRDBBase.h +++ b/include/phasar/DB/ProjectIRDBBase.h @@ -112,7 +112,7 @@ template class ProjectIRDBBase { /// module for this function to work [[nodiscard]] size_t getInstructionId(n_t Inst) const { assert(isValid()); - return self().getInstructionId(Inst); + return self().getInstructionIdImpl(Inst); } [[nodiscard]] decltype(auto) getAllInstructions() const { diff --git a/include/phasar/Utils/MaybeUniquePtr.h b/include/phasar/Utils/MaybeUniquePtr.h index 4a20f6e758..d5d0dd1aaf 100644 --- a/include/phasar/Utils/MaybeUniquePtr.h +++ b/include/phasar/Utils/MaybeUniquePtr.h @@ -79,7 +79,7 @@ class MaybeUniquePtr : detail::MaybeUniquePtrBase { : detail::MaybeUniquePtrBase( std::exchange(Other.Data, {})) {} - void swap(MaybeUniquePtr &Other) noexcept { std::swap(Data, Other, Data); } + void swap(MaybeUniquePtr &Other) noexcept { std::swap(Data, Other.Data); } friend void swap(MaybeUniquePtr &LHS, MaybeUniquePtr &RHS) noexcept { LHS.swap(RHS); From e567a06667964062126f121556c42069f01002f4 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 21 Apr 2023 10:30:50 +0200 Subject: [PATCH 02/14] Add utils to LLVMIRToSrc --- include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h | 24 +++-- lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp | 88 +++++++++++-------- 2 files changed, 66 insertions(+), 46 deletions(-) diff --git a/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h b/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h index 1c6013f618..cc799fc3ec 100644 --- a/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h +++ b/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h @@ -29,25 +29,31 @@ class Function; class Value; class GlobalVariable; class Module; +class DIFile; } // namespace llvm namespace psr { -std::string getVarNameFromIR(const llvm::Value *V); +[[nodiscard]] std::string getVarNameFromIR(const llvm::Value *V); -std::string getFunctionNameFromIR(const llvm::Value *V); +[[nodiscard]] std::string getFunctionNameFromIR(const llvm::Value *V); -std::string getFilePathFromIR(const llvm::Value *V); +[[nodiscard]] std::string getFilePathFromIR(const llvm::Value *V); -std::string getDirectoryFromIR(const llvm::Value *V); +[[nodiscard]] std::string getDirectoryFromIR(const llvm::Value *V); -unsigned int getLineFromIR(const llvm::Value *V); +[[nodiscard]] const llvm::DIFile *getDIFileFromIR(const llvm::Value *V); -unsigned int getColumnFromIR(const llvm::Value *V); +[[nodiscard]] unsigned int getLineFromIR(const llvm::Value *V); -std::string getSrcCodeFromIR(const llvm::Value *V); +[[nodiscard]] unsigned int getColumnFromIR(const llvm::Value *V); -std::string getModuleIDFromIR(const llvm::Value *V); +[[nodiscard]] std::pair +getLineAndColFromIR(const llvm::Value *V); + +[[nodiscard]] std::string getSrcCodeFromIR(const llvm::Value *V); + +[[nodiscard]] std::string getModuleIDFromIR(const llvm::Value *V); struct SourceCodeInfo { std::string SourceCodeLine; @@ -76,7 +82,7 @@ void from_json(const nlohmann::json &J, SourceCodeInfo &Info); /// SourceCodeInfo void to_json(nlohmann::json &J, const SourceCodeInfo &Info); -SourceCodeInfo getSrcCodeInfoFromIR(const llvm::Value *V); +[[nodiscard]] SourceCodeInfo getSrcCodeInfoFromIR(const llvm::Value *V); } // namespace psr diff --git a/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp b/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp index 6e0b45f4c8..c14cecc1e2 100644 --- a/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp +++ b/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp @@ -103,32 +103,6 @@ llvm::DILocation *getDILocation(const llvm::Value *V) { return nullptr; } -llvm::DIFile *getDIFile(const llvm::Value *V) { - if (const auto *GO = llvm::dyn_cast(V)) { - if (auto *MN = GO->getMetadata(llvm::LLVMContext::MD_dbg)) { - if (auto *Subpr = llvm::dyn_cast(MN)) { - return Subpr->getFile(); - } - if (auto *GVExpr = llvm::dyn_cast(MN)) { - return GVExpr->getVariable()->getFile(); - } - } - } else if (const auto *Arg = llvm::dyn_cast(V)) { - if (auto *LocVar = getDILocalVariable(Arg)) { - return LocVar->getFile(); - } - } else if (const auto *I = llvm::dyn_cast(V)) { - if (I->isUsedByMetadata()) { - if (auto *LocVar = getDILocalVariable(I)) { - return LocVar->getFile(); - } - } else if (I->getMetadata(llvm::LLVMContext::MD_dbg)) { - return I->getDebugLoc()->getFile(); - } - } - return nullptr; -} - std::string getVarNameFromIR(const llvm::Value *V) { if (auto *LocVar = getDILocalVariable(V)) { return LocVar->getName().str(); @@ -154,7 +128,7 @@ std::string getFunctionNameFromIR(const llvm::Value *V) { } std::string getFilePathFromIR(const llvm::Value *V) { - if (auto *DIF = getDIFile(V)) { + if (auto *DIF = getDIFileFromIR(V)) { std::filesystem::path File(DIF->getFilename().str()); std::filesystem::path Dir(DIF->getDirectory().str()); if (!File.empty()) { @@ -181,32 +155,58 @@ std::string getFilePathFromIR(const llvm::Value *V) { return ""; } -unsigned int getLineFromIR(const llvm::Value *V) { +const llvm::DIFile *getDIFileFromIR(const llvm::Value *V) { + if (const auto *GO = llvm::dyn_cast(V)) { + if (auto *MN = GO->getMetadata(llvm::LLVMContext::MD_dbg)) { + if (auto *Subpr = llvm::dyn_cast(MN)) { + return Subpr->getFile(); + } + if (auto *GVExpr = llvm::dyn_cast(MN)) { + return GVExpr->getVariable()->getFile(); + } + } + } else if (const auto *Arg = llvm::dyn_cast(V)) { + if (auto *LocVar = getDILocalVariable(Arg)) { + return LocVar->getFile(); + } + } else if (const auto *I = llvm::dyn_cast(V)) { + if (I->isUsedByMetadata()) { + if (auto *LocVar = getDILocalVariable(I)) { + return LocVar->getFile(); + } + } else if (I->getMetadata(llvm::LLVMContext::MD_dbg)) { + return I->getDebugLoc()->getFile(); + } + } + return nullptr; +} + +std::string getDirectoryFromIR(const llvm::Value *V) { // Argument and Instruction if (auto *DILoc = getDILocation(V)) { - return DILoc->getLine(); + return DILoc->getDirectory().str(); } if (auto *DISubpr = getDISubprogram(V)) { // Function - return DISubpr->getLine(); + return DISubpr->getDirectory().str(); } if (auto *DIGV = getDIGlobalVariable(V)) { // Globals - return DIGV->getLine(); + return DIGV->getDirectory().str(); } - return 0; + return ""; } -std::string getDirectoryFromIR(const llvm::Value *V) { +unsigned int getLineFromIR(const llvm::Value *V) { // Argument and Instruction if (auto *DILoc = getDILocation(V)) { - return DILoc->getDirectory().str(); + return DILoc->getLine(); } if (auto *DISubpr = getDISubprogram(V)) { // Function - return DISubpr->getDirectory().str(); + return DISubpr->getLine(); } if (auto *DIGV = getDIGlobalVariable(V)) { // Globals - return DIGV->getDirectory().str(); + return DIGV->getLine(); } - return ""; + return 0; } unsigned int getColumnFromIR(const llvm::Value *V) { @@ -217,6 +217,20 @@ unsigned int getColumnFromIR(const llvm::Value *V) { return 0; } +std::pair getLineAndColFromIR(const llvm::Value *V) { + // Argument and Instruction + if (auto *DILoc = getDILocation(V)) { + return {DILoc->getLine(), DILoc->getColumn()}; + } + if (auto *DISubpr = getDISubprogram(V)) { // Function + return {DISubpr->getLine(), 0}; + } + if (auto *DIGV = getDIGlobalVariable(V)) { // Globals + return {DIGV->getLine(), 0}; + } + return {0, 0}; +} + std::string getSrcCodeFromIR(const llvm::Value *V) { unsigned int LineNr = getLineFromIR(V); if (LineNr > 0) { From e870d87649c7260cea56f7f7c1ac2f5dbb94f3d4 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Mon, 24 Apr 2023 14:29:27 +0200 Subject: [PATCH 03/14] Make the Container type parameter of the flow function templates actually settable --- .../phasar/DataFlow/IfdsIde/FlowFunctions.h | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/FlowFunctions.h b/include/phasar/DataFlow/IfdsIde/FlowFunctions.h index 13fcb3bac9..0aadfaebf4 100644 --- a/include/phasar/DataFlow/IfdsIde/FlowFunctions.h +++ b/include/phasar/DataFlow/IfdsIde/FlowFunctions.h @@ -22,6 +22,7 @@ #include "llvm/ADT/ArrayRef.h" #include +#include #include #include #include @@ -133,11 +134,8 @@ template > auto identityFlow() { /// v v v v v /// x1 x2 x x3 x4 /// -template , - typename = std::enable_if_t< - std::is_invocable_v && - std::is_convertible_v, Container>>> -auto lambdaFlow(Fn &&F) { +template auto lambdaFlow(Fn &&F) { + using Container = std::invoke_result_t; struct LambdaFlow final : public FlowFunction { LambdaFlow(Fn &&F) : Flow(std::forward(F)) {} Container computeTargets(D Source) override { @@ -204,7 +202,8 @@ auto generateFlow(psr::type_identity_t FactToGenerate, D From) { /// f(x) = {v, x} if p(x) == true /// f(x) = {x} else. /// -template , +template , + typename Fn = psr::TrueFn, typename = std::enable_if_t>> auto generateFlowIf(D FactToGenerate, Fn Predicate) { struct GenFlowIf final : public FlowFunction { @@ -243,7 +242,8 @@ auto generateFlowIf(D FactToGenerate, Fn Predicate) { /// v v v v ... \ v ... /// x w v1 v2 ... vN u /// -template , +template , + typename Range = std::initializer_list, typename = std::enable_if_t>> auto generateManyFlows(Range &&FactsToGenerate, D From) { struct GenMany final : public FlowFunction { @@ -319,7 +319,8 @@ auto killFlow(D FactToKill) { /// f(x) = {} if p(x) == true /// f(x) = {x} else. /// -template , +template , + typename Fn = psr::TrueFn, typename = std::enable_if_t>> auto killFlowIf(Fn Predicate) { struct KillFlowIf final : public FlowFunction { @@ -357,7 +358,8 @@ auto killFlowIf(Fn Predicate) { /// v v /// u v1 v2 ... vN w ... /// -template , +template , + typename Range = std::initializer_list, typename = std::enable_if_t>> auto killManyFlows(Range &&FactsToKill) { struct KillMany final : public FlowFunction { @@ -465,7 +467,8 @@ auto generateFlowAndKillAllOthers(psr::type_identity_t FactToGenerate, /// v v v ... \ ... /// x w v1 v2 ... vN u /// -template , +template , + typename Range = std::initializer_list, typename = std::enable_if_t>> auto generateManyFlowsAndKillAllOthers(Range &&FactsToGenerate, D From) { struct GenManyAndKillAllOthers final : public FlowFunction { From 3cb63281dc59e4f3076394a294a964e35664b786 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Wed, 26 Apr 2023 10:07:06 +0200 Subject: [PATCH 04/14] Fix recursive template instantiation in C++20 mode --- include/phasar/DataFlow/IfdsIde/EdgeFunction.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h index ca75fd53df..e872c23fb8 100644 --- a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h @@ -58,8 +58,8 @@ template concept IsEdgeFunction = requires(const T &EF, const EdgeFunction& TEEF, EdgeFunctionRef CEF, typename T::l_t Src) { typename T::l_t; {EF.computeTarget(Src)} -> std::convertible_to; - {T::compose(CEF, TEEF)} -> std::convertible_to>; - {T::join(CEF, TEEF)} -> std::convertible_to>; + {T::compose(CEF, TEEF)} -> std::same_as>; + {T::join(CEF, TEEF)} -> std::same_as>; }; // clang-format on From 91833daf7045c76062bd4489fb8db2d9f9166c88 Mon Sep 17 00:00:00 2001 From: Sriteja Kummita Date: Wed, 3 May 2023 11:15:46 +0200 Subject: [PATCH 05/14] feat: boolean to toggle trim --- include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h | 3 ++- lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h b/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h index cc799fc3ec..9084819764 100644 --- a/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h +++ b/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h @@ -51,7 +51,8 @@ namespace psr { [[nodiscard]] std::pair getLineAndColFromIR(const llvm::Value *V); -[[nodiscard]] std::string getSrcCodeFromIR(const llvm::Value *V); +[[nodiscard]] std::string getSrcCodeFromIR(const llvm::Value *V, + bool Trim = true); [[nodiscard]] std::string getModuleIDFromIR(const llvm::Value *V); diff --git a/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp b/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp index c14cecc1e2..3f1a3e83b3 100644 --- a/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp +++ b/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp @@ -231,7 +231,7 @@ std::pair getLineAndColFromIR(const llvm::Value *V) { return {0, 0}; } -std::string getSrcCodeFromIR(const llvm::Value *V) { +std::string getSrcCodeFromIR(const llvm::Value *V, bool Trim) { unsigned int LineNr = getLineFromIR(V); if (LineNr > 0) { std::filesystem::path Path(getFilePathFromIR(V)); @@ -244,7 +244,7 @@ std::string getSrcCodeFromIR(const llvm::Value *V) { Ifs.ignore(std::numeric_limits::max(), '\n'); } std::getline(Ifs, SrcLine); - return llvm::StringRef(SrcLine).trim().str(); + return Trim ? llvm::StringRef(SrcLine).trim().str() : SrcLine; } } } From 29aafdf564b9c61b57de398e8cef477cddda9f33 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sun, 7 May 2023 18:58:51 +0200 Subject: [PATCH 06/14] Fix fromMetaDataId + add deserialization support for LLVMBasedICFG --- .../PhasarLLVM/ControlFlow/LLVMBasedICFG.h | 3 + include/phasar/PhasarLLVM/HelperAnalyses.h | 2 + .../phasar/PhasarLLVM/HelperAnalysisConfig.h | 1 + lib/Controller/AnalysisController.cpp | 5 + lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp | 68 ++++++-- lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp | 2 +- lib/PhasarLLVM/HelperAnalyses.cpp | 20 ++- lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp | 2 +- tools/phasar-cli/phasar-cli.cpp | 35 +++- .../PhasarLLVM/ControlFlow/CMakeLists.txt | 1 + .../LLVMBasedICFGSerializationTest.cpp | 155 ++++++++++++++++++ 11 files changed, 267 insertions(+), 27 deletions(-) create mode 100644 unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h index 3878aa1557..9570ad1bad 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h @@ -89,6 +89,9 @@ class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase { Soundness S = Soundness::Soundy, bool IncludeGlobals = true); + explicit LLVMBasedICFG(LLVMProjectIRDB *IRDB, + const nlohmann::json &SerializedCG); + ~LLVMBasedICFG(); LLVMBasedICFG(const LLVMBasedICFG &) = delete; diff --git a/include/phasar/PhasarLLVM/HelperAnalyses.h b/include/phasar/PhasarLLVM/HelperAnalyses.h index 07b09878d7..ebaabdcbf8 100644 --- a/include/phasar/PhasarLLVM/HelperAnalyses.h +++ b/include/phasar/PhasarLLVM/HelperAnalyses.h @@ -33,6 +33,7 @@ class HelperAnalyses { // NOLINT(cppcoreguidelines-special-member-functions) std::optional PrecomputedPTS, AliasAnalysisType PTATy, bool AllowLazyPTS, std::vector EntryPoints, + std::optional PrecomputedCG, CallGraphAnalysisType CGTy, Soundness SoundnessLevel, bool AutoGlobalSupport) noexcept; @@ -69,6 +70,7 @@ class HelperAnalyses { // NOLINT(cppcoreguidelines-special-member-functions) bool AllowLazyPTS{}; // ICF + std::optional PrecomputedCG; std::vector EntryPoints; CallGraphAnalysisType CGTy{}; Soundness SoundnessLevel{}; diff --git a/include/phasar/PhasarLLVM/HelperAnalysisConfig.h b/include/phasar/PhasarLLVM/HelperAnalysisConfig.h index d35195e763..21b52a958f 100644 --- a/include/phasar/PhasarLLVM/HelperAnalysisConfig.h +++ b/include/phasar/PhasarLLVM/HelperAnalysisConfig.h @@ -21,6 +21,7 @@ namespace psr { struct HelperAnalysisConfig { std::optional PrecomputedPTS = std::nullopt; + std::optional PrecomputedCG = std::nullopt; AliasAnalysisType PTATy = AliasAnalysisType::CFLAnders; CallGraphAnalysisType CGTy = CallGraphAnalysisType::OTF; Soundness SoundnessLevel = Soundness::Soundy; diff --git a/lib/Controller/AnalysisController.cpp b/lib/Controller/AnalysisController.cpp index 5e9d1413d4..c3ad51db1b 100644 --- a/lib/Controller/AnalysisController.cpp +++ b/lib/Controller/AnalysisController.cpp @@ -9,6 +9,7 @@ #include "phasar/Controller/AnalysisController.h" +#include "phasar//Utils/NlohmannLogging.h" #include "phasar/AnalysisStrategy/Strategies.h" #include "phasar/Controller/AnalysisControllerEmitterOptions.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" @@ -184,6 +185,10 @@ void AnalysisController::emitRequestedHelperAnalysisResults() { WithResultFileOrStdout("/psr-cg.txt", [this](auto &OS) { HA.getICFG().print(OS); }); } + if (EmitterOptions & AnalysisControllerEmitterOptions::EmitCGAsJson) { + WithResultFileOrStdout( + "/psr-cg.json", [this](auto &OS) { OS << HA.getICFG().getAsJson(); }); + } if (EmitterOptions & (AnalysisControllerEmitterOptions::EmitStatisticsAsJson | diff --git a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp index 974988ae6d..3f97e7f950 100644 --- a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp +++ b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp @@ -366,9 +366,8 @@ LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB, llvm::ArrayRef EntryPoints, LLVMTypeHierarchy *TH, LLVMAliasInfoRef PT, Soundness S, bool IncludeGlobals) - : TH(TH) { + : IRDB(IRDB), TH(TH) { assert(IRDB != nullptr); - this->IRDB = IRDB; Builder B{IRDB, this, PT}; LLVMAliasInfo PTOwn; @@ -398,6 +397,51 @@ LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB, << std::chrono::steady_clock::now().time_since_epoch().count()); } +LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB, + const nlohmann::json &SerializedCG) + : IRDB(IRDB) { + assert(IRDB != nullptr); + + // llvm::outs() << "Load precomputed call-graph from JSON\n"; + + auto It = SerializedCG.find(PhasarConfig::JsonCallGraphID().str()); + + if (It == SerializedCG.end()) { + PHASAR_LOG_LEVEL_CAT(ERROR, "LLVMBasedICFG", + "Cannot deserialize call-graph from JSON: No key '" + << PhasarConfig::JsonCallGraphID() << "' present"); + return; + } + + const auto &Edges = It.value(); + + CallersOf.reserve(Edges.size()); + CalleesAt.reserve(Edges.size()); + VertexFunctions.reserve(Edges.size()); + + for (const auto &[FunName, CallerIDs] : Edges.items()) { + const auto *Fun = IRDB->getFunction(FunName); + if (!Fun) { + PHASAR_LOG_LEVEL_CAT(WARNING, "LLVMBasedICFG", + "Invalid function name: " << FunName); + continue; + } + auto *CEdges = addFunctionVertex(Fun); + CEdges->reserve(CallerIDs.size()); + + for (const auto &JId : CallerIDs) { + auto Id = JId.get(); + const auto *CS = IRDB->getInstruction(Id); + if (!CS) { + PHASAR_LOG_LEVEL_CAT(WARNING, "LLVMBasedICFG", + "Invalid CAll-Instruction Id: " << Id); + } + + addCallEdge(CS, Fun); + } + } +} + LLVMBasedICFG::~LLVMBasedICFG() = default; [[nodiscard]] FunctionRange LLVMBasedICFG::getAllFunctionsImpl() const { @@ -504,22 +548,12 @@ void LLVMBasedICFG::printImpl(llvm::raw_ostream &OS) const { [[nodiscard]] nlohmann::json LLVMBasedICFG::getAsJsonImpl() const { nlohmann::json J; - for (size_t Vtx = 0, VtxEnd = VertexFunctions.size(); Vtx != VtxEnd; ++Vtx) { - auto VtxFunName = VertexFunctions[Vtx]->getName().str(); - J[PhasarConfig::JsonCallGraphID().str()][VtxFunName] = - nlohmann::json::array(); - - for (const auto &Inst : llvm::instructions(VertexFunctions[Vtx])) { - if (!llvm::isa(Inst)) { - continue; - } + auto &Edges = J[PhasarConfig::JsonCallGraphID().str()]; + for (const auto &[Fun, Callers] : CallersOf) { + auto &JCallers = Edges[Fun->getName().str()]; - if (auto It = CalleesAt.find(&Inst); It != CalleesAt.end()) { - for (const auto *Succ : *It->second) { - J[PhasarConfig::JsonCallGraphID().str()][VtxFunName].push_back( - Succ->getName().str()); - } - } + for (const auto *CS : *Callers) { + JCallers.push_back(IRDB->getInstructionId(CS)); } } diff --git a/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp b/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp index 17f05d6c81..d06b52acc0 100644 --- a/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp +++ b/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp @@ -260,5 +260,5 @@ const llvm::Value *psr::fromMetaDataId(const LLVMProjectIRDB &IRDB, } auto IdNr = ParseInt(Id); - return IdNr ? IRDB.getInstruction(*IdNr) : nullptr; + return IdNr ? IRDB.getValueFromId(*IdNr) : nullptr; } diff --git a/lib/PhasarLLVM/HelperAnalyses.cpp b/lib/PhasarLLVM/HelperAnalyses.cpp index 42700df9d4..e0d13925e0 100644 --- a/lib/PhasarLLVM/HelperAnalyses.cpp +++ b/lib/PhasarLLVM/HelperAnalyses.cpp @@ -13,11 +13,13 @@ HelperAnalyses::HelperAnalyses(std::string IRFile, std::optional PrecomputedPTS, AliasAnalysisType PTATy, bool AllowLazyPTS, std::vector EntryPoints, + std::optional PrecomputedCG, CallGraphAnalysisType CGTy, Soundness SoundnessLevel, bool AutoGlobalSupport) noexcept : IRFile(std::move(IRFile)), PrecomputedPTS(std::move(PrecomputedPTS)), PTATy(PTATy), AllowLazyPTS(AllowLazyPTS), + PrecomputedCG(std::move(PrecomputedCG)), EntryPoints(std::move(EntryPoints)), CGTy(CGTy), SoundnessLevel(SoundnessLevel), AutoGlobalSupport(AutoGlobalSupport) {} @@ -26,8 +28,10 @@ HelperAnalyses::HelperAnalyses(std::string IRFile, HelperAnalysisConfig Config) noexcept : IRFile(std::move(IRFile)), PrecomputedPTS(std::move(Config.PrecomputedPTS)), PTATy(Config.PTATy), - AllowLazyPTS(Config.AllowLazyPTS), EntryPoints(std::move(EntryPoints)), - CGTy(Config.CGTy), SoundnessLevel(Config.SoundnessLevel), + AllowLazyPTS(Config.AllowLazyPTS), + PrecomputedCG(std::move(Config.PrecomputedCG)), + EntryPoints(std::move(EntryPoints)), CGTy(Config.CGTy), + SoundnessLevel(Config.SoundnessLevel), AutoGlobalSupport(Config.AutoGlobalSupport) {} HelperAnalyses::HelperAnalyses(const llvm::Twine &IRFile, @@ -70,10 +74,14 @@ LLVMTypeHierarchy &HelperAnalyses::getTypeHierarchy() { LLVMBasedICFG &HelperAnalyses::getICFG() { if (!ICF) { - ICF = std::make_unique( - &getProjectIRDB(), CGTy, std::move(EntryPoints), &getTypeHierarchy(), - CGTy == CallGraphAnalysisType::OTF ? &getAliasInfo() : nullptr, - SoundnessLevel, AutoGlobalSupport); + if (PrecomputedCG.has_value()) { + ICF = std::make_unique(&getProjectIRDB(), *PrecomputedCG); + } else { + ICF = std::make_unique( + &getProjectIRDB(), CGTy, std::move(EntryPoints), &getTypeHierarchy(), + CGTy == CallGraphAnalysisType::OTF ? &getAliasInfo() : nullptr, + SoundnessLevel, AutoGlobalSupport); + } } return *ICF; diff --git a/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp b/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp index 2e7badc4da..203e16c7b2 100644 --- a/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp +++ b/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp @@ -100,7 +100,7 @@ LLVMAliasSet::LLVMAliasSet(LLVMProjectIRDB *IRDB, assert(IRDB != nullptr); // Assume, we already have validated the json schema - llvm::outs() << "Load precomputed points-to info from JSON\n"; + // llvm::outs() << "Load precomputed points-to info from JSON\n"; const auto &Sets = SerializedPTS.at("AliasSets"); assert(Sets.is_array()); diff --git a/tools/phasar-cli/phasar-cli.cpp b/tools/phasar-cli/phasar-cli.cpp index 1ac2672d70..ef221b8cd3 100644 --- a/tools/phasar-cli/phasar-cli.cpp +++ b/tools/phasar-cli/phasar-cli.cpp @@ -169,7 +169,6 @@ cl::opt cl::opt ProjectIdOpt("project-id", cl::desc("Project id used for output"), - cl::init("default-phasar-project"), cl::cat(PsrCat), cl::Hidden); PSR_SHORTLONG_OPTION(OutDirOpt, std::string, "O", "out", @@ -233,6 +232,12 @@ cl::opt "via emit-pta-as-json from the given file"), cl::cat(PsrCat)); +cl::opt LoadCGFromJsonOpt( + "load-cg-from-json", + cl::desc("Load the persisted call-graph previously exported via " + "emit-cg-as-json from the given file"), + cl::cat(PsrCat)); + PSR_SHORTLONG_OPTION(PammOutOpt, std::string, "A", "pamm-out", "Filename for PAMM's gathered data", cl::init("PAMM_data.json"), cl::cat(PsrCat), cl::Hidden); @@ -344,6 +349,15 @@ int main(int Argc, const char **Argv) { return 1; } + if (ProjectIdOpt.empty()) { + ProjectIdOpt = std::filesystem::path(ModuleOpt.getValue()) + .filename() + .replace_extension(); + if (ProjectIdOpt.empty()) { + ProjectIdOpt = "default-phasar-project"; + } + } + validateParamModule(); validateParamOutput(); validateParamPointerAnalysis(); @@ -385,6 +399,15 @@ int main(int Argc, const char **Argv) { if (EmitCGAsDotOpt) { EmitterOptions |= AnalysisControllerEmitterOptions::EmitCGAsDot; } + if (EmitCGAsJsonOpt) { + EmitterOptions |= AnalysisControllerEmitterOptions::EmitCGAsJson; + } + if (EmitCGAsTextOpt) { + llvm::errs() + << "ERROR: emit-cg-as-text is currently not supported. Did you mean " + "emit-cg-as-dot? For reversible serialization use emit-cg-as-json\n"; + return 1; + } if (EmitPTAAsTextOpt) { EmitterOptions |= AnalysisControllerEmitterOptions::EmitPTAAsText; } @@ -410,9 +433,16 @@ int main(int Argc, const char **Argv) { std::optional PrecomputedAliasSet; if (!LoadPTAFromJsonOpt.empty()) { + PHASAR_LOG_LEVEL(INFO, "Load AliasInfo from file: " << LoadCGFromJsonOpt); PrecomputedAliasSet = readJsonFile(LoadPTAFromJsonOpt); } + std::optional PrecomputedCallGraph; + if (!LoadCGFromJsonOpt.empty()) { + PHASAR_LOG_LEVEL(INFO, "Load CallGraph from file: " << LoadCGFromJsonOpt); + PrecomputedCallGraph = readJsonFile(LoadCGFromJsonOpt); + } + if (EntryOpt.empty()) { EntryOpt.push_back("main"); } @@ -421,7 +451,8 @@ int main(int Argc, const char **Argv) { HelperAnalyses HA(std::move(ModuleOpt.getValue()), std::move(PrecomputedAliasSet), AliasTypeOpt, !AnalysisController::needsToEmitPTA(EmitterOptions), - EntryOpt, CGTypeOpt, SoundnessOpt, AutoGlobalsOpt); + EntryOpt, std::move(PrecomputedCallGraph), CGTypeOpt, + SoundnessOpt, AutoGlobalsOpt); AnalysisController Controller( HA, DataFlowAnalysisOpt, {AnalysisConfigOpt.getValue()}, EntryOpt, diff --git a/unittests/PhasarLLVM/ControlFlow/CMakeLists.txt b/unittests/PhasarLLVM/ControlFlow/CMakeLists.txt index a7d45fd5fa..04cb11d947 100644 --- a/unittests/PhasarLLVM/ControlFlow/CMakeLists.txt +++ b/unittests/PhasarLLVM/ControlFlow/CMakeLists.txt @@ -9,6 +9,7 @@ set(ControlFlowSources LLVMBasedBackwardICFGTest.cpp LLVMBasedICFGExportTest.cpp LLVMBasedICFGGlobCtorDtorTest.cpp + LLVMBasedICFGSerializationTest.cpp ) foreach(TEST_SRC ${ControlFlowSources}) diff --git a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp new file mode 100644 index 0000000000..6bf60c325e --- /dev/null +++ b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp @@ -0,0 +1,155 @@ + +#include "phasar/ControlFlow/CallGraphAnalysisType.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" + +#include "TestConfig.h" +#include "gtest/gtest.h" + +class LLVMBasedICFGGSerializationTest : public ::testing::Test { +protected: + static constexpr auto PathToLLFiles = PHASAR_BUILD_SUBFOLDER("call_graphs/"); + + void serAndDeser(const llvm::Twine &IRFile) { + using namespace std::string_literals; + + psr::LLVMProjectIRDB IRDB(PathToLLFiles + IRFile); + + psr::LLVMBasedICFG ICF(&IRDB, psr::CallGraphAnalysisType::OTF, {"main"s}); + auto Ser = ICF.getAsJson(); + + psr::LLVMBasedICFG Deser(&IRDB, Ser); + + compareResults(ICF, Deser); + } + + void compareResults(const psr::LLVMBasedICFG &Orig, + const psr::LLVMBasedICFG &Deser) { + EXPECT_EQ(Orig.getAllVertexFunctions().size(), + Deser.getAllVertexFunctions().size()); + + { + llvm::DenseSet DeserFuns( + Deser.getAllVertexFunctions().begin(), + Deser.getAllVertexFunctions().end()); + for (const auto *Fun : Orig.getAllVertexFunctions()) { + EXPECT_TRUE(DeserFuns.contains(Fun)) + << "Deserialized ICFG does not contain vertex function " + << Fun->getName().str(); + } + } + + for (const auto *Fun : Orig.getAllVertexFunctions()) { + + const auto &Calls = Orig.getCallsFromWithin(Fun); + + for (const auto *CS : Calls) { + llvm::DenseSet DeserCallees( + Deser.getCalleesOfCallAt(CS).begin(), + Deser.getCalleesOfCallAt(CS).end()); + EXPECT_EQ(Orig.getCalleesOfCallAt(CS).size(), DeserCallees.size()); + + for (const auto *OrigCallee : Orig.getCalleesOfCallAt(CS)) { + EXPECT_TRUE(DeserCallees.contains(OrigCallee)) + << "Deserialized ICFG does not contain call to " + << OrigCallee->getName().str() << " from " + << psr::llvmIRToString(CS); + } + } + } + } +}; + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG01) { + serAndDeser("static_callsite_1_c.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG02) { + serAndDeser("static_callsite_2_c.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG03) { + serAndDeser("static_callsite_3_c.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG04) { + serAndDeser("static_callsite_4_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG05) { + serAndDeser("static_callsite_5_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG06) { + serAndDeser("static_callsite_6_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG07) { + serAndDeser("static_callsite_7_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG08) { + serAndDeser("static_callsite_8_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG09) { + serAndDeser("static_callsite_9_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG10) { + serAndDeser("static_callsite_10_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG11) { + serAndDeser("static_callsite_11_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG12) { + serAndDeser("static_callsite_12_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG13) { + serAndDeser("static_callsite_13_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFGV1) { + serAndDeser("virtual_call_1_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFGV2) { + serAndDeser("virtual_call_2_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFGV3) { + serAndDeser("virtual_call_3_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFGV4) { + serAndDeser("virtual_call_4_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFGV5) { + serAndDeser("virtual_call_5_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFGV6) { + serAndDeser("virtual_call_6_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFGV7) { + serAndDeser("virtual_call_7_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFGV8) { + serAndDeser("virtual_call_8_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFGV9) { + serAndDeser("virtual_call_9_cpp.ll"); +} + +int main(int Argc, char **Argv) { + ::testing::InitGoogleTest(&Argc, Argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file From aa86a676c3b2f6206c1c8204bb20317179dfb596 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sun, 7 May 2023 19:12:40 +0200 Subject: [PATCH 07/14] pre-commit --- .../PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp index 6bf60c325e..ec1d476da0 100644 --- a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp +++ b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp @@ -152,4 +152,4 @@ TEST_F(LLVMBasedICFGGSerializationTest, SerICFGV9) { int main(int Argc, char **Argv) { ::testing::InitGoogleTest(&Argc, Argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} From 5e3bc240248744d34e3ffc570678ad53f0d4a220 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Tue, 9 May 2023 15:10:41 +0200 Subject: [PATCH 08/14] IRDB ctor with pre-loaded IR --- .../phasar/PhasarLLVM/DB/LLVMProjectIRDB.h | 6 ++++- lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp | 24 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h b/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h index d1b1789d26..e4800cee85 100644 --- a/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h +++ b/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h @@ -26,6 +26,8 @@ #include +#include + namespace psr { class LLVMProjectIRDB; @@ -48,10 +50,12 @@ class LLVMProjectIRDB : public ProjectIRDBBase { /// CAUTION: Do not manage the same LLVM Module with multiple LLVMProjectIRDB /// instances at the same time! This will confuse the ModulesToSlotTracker explicit LLVMProjectIRDB(llvm::Module *Mod); - /// Initializes the new ProjectIRDB with the given IR Moduleand takes + /// Initializes the new ProjectIRDB with the given IR Module and takes /// ownership of it explicit LLVMProjectIRDB(std::unique_ptr Mod, bool DoPreprocessing = true); + /// Parses the given LLVM IR file and owns the resulting IR Module + explicit LLVMProjectIRDB(llvm::MemoryBufferRef Buf); LLVMProjectIRDB(const LLVMProjectIRDB &) = delete; LLVMProjectIRDB &operator=(LLVMProjectIRDB &) = delete; diff --git a/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp b/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp index d06b52acc0..9f4105a7df 100644 --- a/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp +++ b/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp @@ -107,6 +107,30 @@ LLVMProjectIRDB::LLVMProjectIRDB(std::unique_ptr Mod, } } +LLVMProjectIRDB::LLVMProjectIRDB(llvm::MemoryBufferRef Buf) { + llvm::SMDiagnostic Diag; + std::unique_ptr M = llvm::parseIR(Buf, Diag, Ctx); + bool BrokenDebugInfo = false; + if (M == nullptr) { + Diag.print(nullptr, llvm::errs()); + return; + } + /* Crash in presence of llvm-3.9.1 module (segfault) */ + if (M == nullptr || llvm::verifyModule(*M, &llvm::errs(), &BrokenDebugInfo)) { + PHASAR_LOG_LEVEL(ERROR, Buf.getBufferIdentifier() + << " could not be parsed correctly!"); + return; + } + if (BrokenDebugInfo) { + PHASAR_LOG_LEVEL(WARNING, "Debug info is broken!"); + } + + auto *NonConst = M.get(); + Mod = std::move(M); + ModulesToSlotTracker::setMSTForModule(Mod.get()); + preprocessModule(NonConst); +} + LLVMProjectIRDB::~LLVMProjectIRDB() { if (Mod) { ModulesToSlotTracker::deleteMSTForModule(Mod.get()); From 2399b01b9de49dea03b6f4f1644e9772882b3fbb Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Tue, 9 May 2023 15:45:27 +0200 Subject: [PATCH 09/14] Add chrono utils for formatting std::chrono::duration --- include/phasar/Utils/ChronoUtils.h | 51 ++++++++++++++++++++++++++++++ lib/Utils/ChronoUtils.cpp | 7 ++++ 2 files changed, 58 insertions(+) create mode 100644 include/phasar/Utils/ChronoUtils.h create mode 100644 lib/Utils/ChronoUtils.cpp diff --git a/include/phasar/Utils/ChronoUtils.h b/include/phasar/Utils/ChronoUtils.h new file mode 100644 index 0000000000..2676c2cde0 --- /dev/null +++ b/include/phasar/Utils/ChronoUtils.h @@ -0,0 +1,51 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_UTILS_CHRONO_UTILS_H +#define PHASAR_PHASARLLVM_UTILS_CHRONO_UTILS_H + +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + +#include + +namespace psr { + +struct hms { // NOLINT + std::chrono::hours Hours{}; + std::chrono::minutes Minutes{}; + std::chrono::seconds Seconds{}; + std::chrono::microseconds Micros{}; + + hms() noexcept = default; + hms(std::chrono::nanoseconds NS) noexcept { + using namespace std::chrono; + + Hours = duration_cast(NS); + NS -= Hours; + Minutes = duration_cast(NS); + NS -= Minutes; + Seconds = duration_cast(NS); + NS -= Seconds; + Micros = duration_cast(NS); + } + + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const hms &HMS); + + [[nodiscard]] std::string str() const { + std::string Ret; + llvm::raw_string_ostream OS(Ret); + OS << *this; + return Ret; + } +}; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_UTILS_CHRONO_UTILS_H diff --git a/lib/Utils/ChronoUtils.cpp b/lib/Utils/ChronoUtils.cpp new file mode 100644 index 0000000000..6540baf96c --- /dev/null +++ b/lib/Utils/ChronoUtils.cpp @@ -0,0 +1,7 @@ +#include "phasar/Utils/ChronoUtils.h" + +llvm::raw_ostream &psr::operator<<(llvm::raw_ostream &OS, const hms &HMS) { + return OS << llvm::format("%.2ld:%.2ld:%.2ld:%.6ld", HMS.Hours.count(), + HMS.Minutes.count(), HMS.Seconds.count(), + HMS.Micros.count()); +} From 998bad1bb037d01c9d46d2373910598993991a9b Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Mon, 22 May 2023 16:39:33 +0200 Subject: [PATCH 10/14] Real constness within SolverResults --- .../phasar/DataFlow/IfdsIde/SolverResults.h | 28 +++++------ include/phasar/Utils/DefaultValue.h | 44 +++++++++++++++++ include/phasar/Utils/Table.h | 48 +++++++++++++++---- 3 files changed, 98 insertions(+), 22 deletions(-) create mode 100644 include/phasar/Utils/DefaultValue.h diff --git a/include/phasar/DataFlow/IfdsIde/SolverResults.h b/include/phasar/DataFlow/IfdsIde/SolverResults.h index 0e760878cb..745ea63d6b 100644 --- a/include/phasar/DataFlow/IfdsIde/SolverResults.h +++ b/include/phasar/DataFlow/IfdsIde/SolverResults.h @@ -94,7 +94,7 @@ class SolverResultsBase { std::is_same_v>, llvm::Instruction>, std::unordered_map> - resultsAtInLLVMSSA(ByConstRef Stmt, bool StripZero = false) { + resultsAtInLLVMSSA(ByConstRef Stmt, bool StripZero = false) const { std::unordered_map Result = [this, Stmt]() { if (Stmt->getType()->isVoidTy()) { return self().Results.row(Stmt); @@ -128,7 +128,7 @@ class SolverResultsBase { std::is_same_v>, llvm::Instruction>, l_t> - resultAtInLLVMSSA(ByConstRef Stmt, d_t Value) { + resultAtInLLVMSSA(ByConstRef Stmt, d_t Value) const { if (Stmt->getType()->isVoidTy()) { return self().Results.get(Stmt, Value); } @@ -145,7 +145,7 @@ class SolverResultsBase { void dumpResults(const ICFGTy &ICF, const NodePrinterBase &NP, const DataFlowFactPrinterBase &DP, const EdgeFactPrinterBase &LP, - llvm::raw_ostream &OS = llvm::outs()) { + llvm::raw_ostream &OS = llvm::outs()) const { using f_t = typename ICFGTy::f_t; PAMM_GET_INSTANCE; @@ -195,15 +195,11 @@ class SolverResultsBase { template void dumpResults(const ICFGTy &ICF, const ProblemTy &IDEProblem, - llvm::raw_ostream &OS = llvm::outs()) { + llvm::raw_ostream &OS = llvm::outs()) const { dumpResults(ICF, IDEProblem, IDEProblem, IDEProblem, OS); } private: - [[nodiscard]] Derived &self() noexcept { - static_assert(std::is_base_of_v); - return static_cast(*this); - } [[nodiscard]] const Derived &self() const noexcept { static_assert(std::is_base_of_v); return static_cast(*this); @@ -222,12 +218,12 @@ class SolverResults using typename base_t::l_t; using typename base_t::n_t; - SolverResults(Table &ResTab, ByConstRef ZV) noexcept + SolverResults(const Table &ResTab, ByConstRef ZV) noexcept : Results(ResTab), ZV(ZV) {} SolverResults(Table &&ResTab, ByConstRef ZV) = delete; private: - Table &Results; + const Table &Results; ByConstRef ZV; }; @@ -245,16 +241,20 @@ class OwningSolverResults OwningSolverResults(Table ResTab, D ZV) noexcept(std::is_nothrow_move_constructible_v) - : Results(std::move(ResTab)), ZV(ZV) {} + : Results(std::move(ResTab)), ZV(std::move(ZV)) {} - [[nodiscard]] operator SolverResults() const &noexcept { + [[nodiscard]] SolverResults get() const &noexcept { return {Results, ZV}; } + SolverResults get() && = delete; + + [[nodiscard]] operator SolverResults() const &noexcept { + return get(); + } operator SolverResults() && = delete; private: - // psr::Table is not const-enabled, so we have to give out mutable references - mutable Table Results; + Table Results; D ZV; }; diff --git a/include/phasar/Utils/DefaultValue.h b/include/phasar/Utils/DefaultValue.h new file mode 100644 index 0000000000..c7525d32e4 --- /dev/null +++ b/include/phasar/Utils/DefaultValue.h @@ -0,0 +1,44 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_UTILS_DEFAULTVALUE_H +#define PHASAR_PHASARLLVM_UTILS_DEFAULTVALUE_H + +#include "phasar/Utils/ByRef.h" + +#include +namespace psr { + +/// Gets a (cached) reference to the default-constructed value of type T. If T +/// is small and trivially default constructible, creates a temporary instead. +/// Useful for getters that return ByConstRef but need to handle the +/// non-existing-T case +template >> +[[nodiscard]] ByConstRef +getDefaultValue() noexcept(std::is_nothrow_default_constructible_v) { + auto DefaultConstruct = [] { + if constexpr (std::is_aggregate_v) { + return T{}; + } else { + return T(); + } + }; + + if constexpr (CanEfficientlyPassByValue) { + return DefaultConstruct(); + } else { + static T DefaultVal = DefaultConstruct(); + return DefaultVal; + } +} + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_UTILS_DEFAULTVALUE_H diff --git a/include/phasar/Utils/Table.h b/include/phasar/Utils/Table.h index 6b5511f64e..4d580d9ca5 100644 --- a/include/phasar/Utils/Table.h +++ b/include/phasar/Utils/Table.h @@ -17,10 +17,14 @@ #ifndef PHASAR_UTILS_TABLE_H_ #define PHASAR_UTILS_TABLE_H_ +#include "phasar/Utils/ByRef.h" +#include "phasar/Utils/DefaultValue.h" + #include "llvm/Support/raw_ostream.h" #include #include +#include #include #include @@ -75,11 +79,9 @@ template class Table { void insert(R Row, C Column, V Val) { // Associates the specified value with the specified keys. - Tab[Row][Column] = std::move(Val); + Tab[std::move(Row)][std::move(Column)] = std::move(Val); } - void insert(const Table &T) { Tab.insert(T.table.begin(), T.table.end()); } - void clear() { Tab.clear(); } [[nodiscard]] bool empty() const { return Tab.empty(); } @@ -180,9 +182,26 @@ template class Table { } [[nodiscard]] V &get(R RowKey, C ColumnKey) { - // Returns the value corresponding to the given row and column keys, or null + // Returns the value corresponding to the given row and column keys, or V() // if no such mapping exists. - return Tab[RowKey][ColumnKey]; + return Tab[std::move(RowKey)][std::move(ColumnKey)]; + } + + [[nodiscard]] ByConstRef get(ByConstRef RowKey, + ByConstRef ColumnKey) const noexcept { + // Returns the value corresponding to the given row and column keys, or V() + // if no such mapping exists. + auto OuterIt = Tab.find(RowKey); + if (OuterIt == Tab.end()) { + return getDefaultValue(); + } + + auto It = OuterIt->second.find(ColumnKey); + if (It == OuterIt->second.end()) { + return getDefaultValue(); + } + + return It->second; } V remove(R RowKey, C ColumnKey) { @@ -199,6 +218,16 @@ template class Table { return Tab[RowKey]; } + [[nodiscard]] ByConstRef> + row(ByConstRef RowKey) const noexcept { + // Returns a view of all mappings that have the given row key. + auto It = Tab.find(RowKey); + if (It == Tab.end()) { + return getDefaultValue>(); + } + return It->second; + } + [[nodiscard]] std::multiset rowKeySet() const { // Returns a set of row keys that have one or more values in the table. std::multiset Result; @@ -208,7 +237,8 @@ template class Table { return Result; } - [[nodiscard]] std::unordered_map> rowMap() const { + [[nodiscard]] const std::unordered_map> & + rowMap() const noexcept { // Returns a view that associates each row key with the corresponding map // from column keys to values. return Tab; @@ -225,11 +255,13 @@ template class Table { return Result; } - friend bool operator==(const Table &Lhs, const Table &Rhs) { + friend bool operator==(const Table &Lhs, + const Table &Rhs) noexcept { return Lhs.table == Rhs.table; } - friend bool operator<(const Table &Lhs, const Table &Rhs) { + friend bool operator<(const Table &Lhs, + const Table &Rhs) noexcept { return Lhs.table < Rhs.table; } From 7071278146b5c91df2efe5e01ecc0195d872a898 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 26 May 2023 09:39:03 +0200 Subject: [PATCH 11/14] Improve Table + minor --- .../DataFlow/IfdsIde/Solver/IDESolver.h | 33 ++-- include/phasar/Utils/EquivalenceClassMap.h | 9 +- include/phasar/Utils/Table.h | 178 ++++++++---------- lib/Controller/AnalysisController.cpp | 10 +- 4 files changed, 96 insertions(+), 134 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index 4564a2489b..79831d8110 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -1213,7 +1213,6 @@ class IDESolver { } void printIncomingTab() const { -#ifdef DYNAMIC_LOG IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Start of incomingtab entry"); for (const auto &Cell @@ -1231,29 +1230,27 @@ class IDESolver { } PHASAR_LOG_LEVEL(DEBUG, "---------------"); } PHASAR_LOG_LEVEL(DEBUG, "End of incomingtab entry");) -#endif } void printEndSummaryTab() const { -#ifdef DYNAMIC_LOG IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Start of endsummarytab entry"); - for (const auto &Cell - : EndsummaryTab.cellVec()) { - PHASAR_LOG_LEVEL(DEBUG, - "sP: " << IDEProblem.NtoString(Cell.getRowKey())); - PHASAR_LOG_LEVEL(DEBUG, - "d1: " << IDEProblem.DtoString(Cell.getColumnKey())); - for (const auto &InnerCell : Cell.getValue().cellVec()) { - PHASAR_LOG_LEVEL( - DEBUG, " eP: " << IDEProblem.NtoString(InnerCell.getRowKey())); - PHASAR_LOG_LEVEL(DEBUG, " d2: " << IDEProblem.DtoString( - InnerCell.getColumnKey())); - PHASAR_LOG_LEVEL(DEBUG, " EF: " << InnerCell.getValue()); - } + + EndsummaryTab.foreachCell([this](const auto &Row, const auto &Col, + const auto &Val) { + PHASAR_LOG_LEVEL(DEBUG, "sP: " << IDEProblem.NtoString(Row)); + PHASAR_LOG_LEVEL(DEBUG, "d1: " << IDEProblem.DtoString(Col)); + + Val.foreachCell([this](const auto &InnerRow, const auto &InnerCol, + const auto &InnerVal) { + PHASAR_LOG_LEVEL(DEBUG, " eP: " << IDEProblem.NtoString(InnerRow)); + PHASAR_LOG_LEVEL(DEBUG, " d2: " << IDEProblem.DtoString(InnerCol)); + PHASAR_LOG_LEVEL(DEBUG, " EF: " << InnerVal); + }); PHASAR_LOG_LEVEL(DEBUG, "---------------"); - } PHASAR_LOG_LEVEL(DEBUG, "End of endsummarytab entry");) -#endif + }); + + PHASAR_LOG_LEVEL(DEBUG, "End of endsummarytab entry");) } void printComputedPathEdges() { diff --git a/include/phasar/Utils/EquivalenceClassMap.h b/include/phasar/Utils/EquivalenceClassMap.h index 7c84a168da..c93508fe3c 100644 --- a/include/phasar/Utils/EquivalenceClassMap.h +++ b/include/phasar/Utils/EquivalenceClassMap.h @@ -10,6 +10,7 @@ #ifndef PHASAR_UTILS_EQUIVALENCECLASSMAP_H #define PHASAR_UTILS_EQUIVALENCECLASSMAP_H +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/iterator_range.h" #include @@ -148,10 +149,10 @@ template struct EquivalenceClassMap { } [[nodiscard]] const_iterator find(key_type Key) const { - return find_if(StoredData.begin(), StoredData.end(), - [&Key](const EquivalenceClassBucketT &Val) -> bool { - return Val.first.count(Key) >= 1; - }); + return llvm::find_if(StoredData, + [&Key](const EquivalenceClassBucketT &Val) -> bool { + return Val.first.count(Key) >= 1; + }); } [[nodiscard]] std::optional findValue(key_type Key) const { diff --git a/include/phasar/Utils/Table.h b/include/phasar/Utils/Table.h index 4d580d9ca5..24ac50ac05 100644 --- a/include/phasar/Utils/Table.h +++ b/include/phasar/Utils/Table.h @@ -33,48 +33,42 @@ namespace psr { template class Table { -private: - std::unordered_map> Tab; - public: struct Cell { - Cell() = default; - Cell(R Row, C Col, const V Val) - : Row(Row), Column(Col), Val(std::move(Val)) {} - ~Cell() = default; - Cell(const Cell &) = default; - Cell &operator=(const Cell &) = default; - Cell(Cell &&) noexcept = default; - Cell &operator=(Cell &&) noexcept = default; - - [[nodiscard]] R getRowKey() const { return Row; } - [[nodiscard]] C getColumnKey() const { return Column; } - [[nodiscard]] V getValue() const { return Val; } + Cell() noexcept = default; + Cell(R Row, C Col, V Val) noexcept + : Row(std::move(Row)), Column(std::move(Col)), Value(std::move(Val)) {} + + [[nodiscard]] ByConstRef getRowKey() const noexcept { return Row; } + [[nodiscard]] ByConstRef getColumnKey() const noexcept { return Column; } + [[nodiscard]] ByConstRef getValue() const noexcept { return Value; } friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Cell &Cell) { return OS << "Cell: " << Cell.r << ", " << Cell.c << ", " << Cell.v; } - friend bool operator<(const Cell &Lhs, const Cell &Rhs) { - return std::tie(Lhs.Row, Lhs.Column, Lhs.Val) < - std::tie(Rhs.Row, Rhs.Column, Rhs.Val); + friend bool operator<(const Cell &Lhs, const Cell &Rhs) noexcept { + return std::tie(Lhs.Row, Lhs.Column, Lhs.Value) < + std::tie(Rhs.Row, Rhs.Column, Rhs.Value); } - friend bool operator==(const Cell &Lhs, const Cell &Rhs) { - return std::tie(Lhs.Row, Lhs.Column, Lhs.Val) == - std::tie(Rhs.Row, Rhs.Column, Rhs.Val); + friend bool operator==(const Cell &Lhs, const Cell &Rhs) noexcept { + return std::tie(Lhs.Row, Lhs.Column, Lhs.Value) == + std::tie(Rhs.Row, Rhs.Column, Rhs.Value); } - private: - R Row; - C Column; - V Val; + R Row{}; + C Column{}; + V Value{}; }; - Table() = default; - Table(const Table &T) = default; - Table &operator=(const Table &T) = default; + Table() noexcept = default; + + explicit Table(const Table &T) = default; + Table &operator=(const Table &T) = delete; + Table(Table &&T) noexcept = default; Table &operator=(Table &&T) noexcept = default; + ~Table() = default; void insert(R Row, C Column, V Val) { @@ -82,11 +76,11 @@ template class Table { Tab[std::move(Row)][std::move(Column)] = std::move(Val); } - void clear() { Tab.clear(); } + void clear() noexcept { Tab.clear(); } - [[nodiscard]] bool empty() const { return Tab.empty(); } + [[nodiscard]] bool empty() const noexcept { return Tab.empty(); } - [[nodiscard]] size_t size() const { return Tab.size(); } + [[nodiscard]] size_t size() const noexcept { return Tab.size(); } [[nodiscard]] std::set cellSet() const { // Returns a set of all row key / column key / value triplets. @@ -99,9 +93,25 @@ template class Table { return Result; } + template void foreachCell(Fn Handler) const { + for (const auto &M1 : Tab) { + for (const auto &M2 : M1.second) { + std::invoke(Handler, M1.first, M2.first, M2.second); + } + } + } + template void foreachCell(Fn Handler) { + for (auto &M1 : Tab) { + for (auto &M2 : M1.second) { + std::invoke(Handler, M1.first, M2.first, M2.second); + } + } + } + [[nodiscard]] std::vector cellVec() const { // Returns a vector of all row key / column key / value triplets. std::vector Result; + Result.reserve(Tab.size()); // better than nothing... for (const auto &M1 : Tab) { for (const auto &M2 : M1.second) { Result.emplace_back(M1.first, M2.first, M2.second); @@ -110,7 +120,7 @@ template class Table { return Result; } - [[nodiscard]] std::unordered_map column(C ColumnKey) const { + [[nodiscard]] std::unordered_map column(ByConstRef ColumnKey) const { // Returns a view of all mappings that have the given column key. std::unordered_map Column; for (const auto &Row : Tab) { @@ -121,31 +131,8 @@ template class Table { return Column; } - [[nodiscard]] std::multiset columnKeySet() const { - // Returns a set of column keys that have one or more values in the table. - std::multiset Result; - for (const auto &M1 : Tab) { - for (const auto &M2 : M1.second) { - Result.insert(M2.first); - } - } - return Result; - } - - [[nodiscard]] std::unordered_map> - columnMap() const { - // Returns a view that associates each column key with the corresponding map - // from row keys to values. - std::unordered_map> Result; - for (const auto &M1 : Tab) { - for (const auto &M2 : Tab.second) { - Result[M2.first][M1.first] = M2.second; - } - } - return Result; - } - - [[nodiscard]] bool contains(R RowKey, C ColumnKey) const { + [[nodiscard]] bool contains(ByConstRef RowKey, + ByConstRef ColumnKey) const noexcept { // Returns true if the table contains a mapping with the specified row and // column keys. if (auto RowIter = Tab.find(RowKey); RowIter != Tab.end()) { @@ -154,7 +141,7 @@ template class Table { return false; } - [[nodiscard]] bool containsColumn(C ColumnKey) const { + [[nodiscard]] bool containsColumn(ByConstRef ColumnKey) const noexcept { // Returns true if the table contains a mapping with the specified column. for (const auto &M1 : Tab) { if (M1.second.count(ColumnKey)) { @@ -164,23 +151,11 @@ template class Table { return false; } - [[nodiscard]] bool containsRow(R RowKey) const { + [[nodiscard]] bool containsRow(ByConstRef RowKey) const noexcept { // Returns true if the table contains a mapping with the specified row key. return Tab.count(RowKey); } - [[nodiscard]] bool containsValue(const V &Value) const { - // Returns true if the table contains a mapping with the specified value. - for (const auto &M1 : Tab) { - for (const auto &M2 : M1.second) { - if (Value == M2.second) { - return true; - } - } - } - return false; - } - [[nodiscard]] V &get(R RowKey, C ColumnKey) { // Returns the value corresponding to the given row and column keys, or V() // if no such mapping exists. @@ -204,14 +179,30 @@ template class Table { return It->second; } - V remove(R RowKey, C ColumnKey) { + V remove(ByConstRef RowKey, ByConstRef ColumnKey) { // Removes the mapping, if any, associated with the given keys. - V Val = Tab[RowKey][ColumnKey]; - Tab[RowKey].erase(ColumnKey); - return Val; + + auto OuterIt = Tab.find(RowKey); + if (OuterIt == Tab.end()) { + return V(); + } + + auto It = OuterIt->second.find(ColumnKey); + if (It == OuterIt->second.end()) { + return V(); + } + + auto Ret = std::move(It->second); + + OuterIt->second.erase(It); + if (OuterIt->second.empty()) { + Tab.erase(OuterIt); + } + + return Ret; } - void remove(R RowKey) { Tab.erase(RowKey); } + void remove(ByConstRef RowKey) { Tab.erase(RowKey); } [[nodiscard]] std::unordered_map &row(R RowKey) { // Returns a view of all mappings that have the given row key. @@ -228,15 +219,6 @@ template class Table { return It->second; } - [[nodiscard]] std::multiset rowKeySet() const { - // Returns a set of row keys that have one or more values in the table. - std::multiset Result; - for (const auto &M1 : Tab) { - Result.insert(M1.first); - } - return Result; - } - [[nodiscard]] const std::unordered_map> & rowMap() const noexcept { // Returns a view that associates each row key with the corresponding map @@ -244,30 +226,17 @@ template class Table { return Tab; } - [[nodiscard]] std::multiset values() const { - // Returns a collection of all values, which may contain duplicates. - std::multiset Result; - for (const auto &M1 : Tab) { - for (const auto &M2 : M1.second) { - Result.insert(M2.second); - } - } - return Result; + bool operator==(const Table &Other) noexcept { + return Tab == Other.Tab; } - friend bool operator==(const Table &Lhs, - const Table &Rhs) noexcept { - return Lhs.table == Rhs.table; - } - - friend bool operator<(const Table &Lhs, - const Table &Rhs) noexcept { - return Lhs.table < Rhs.table; + bool operator<(const Table &Other) noexcept { + return Tab < Other.Tab; } friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Table &Tab) { - for (const auto &M1 : Tab.table) { + for (const auto &M1 : Tab.Tab) { for (const auto &M2 : M1.second) { OS << "< " << M1.first << " , " << M2.first << " , " << M2.second << " >\n"; @@ -275,6 +244,9 @@ template class Table { } return OS; } + +private: + std::unordered_map> Tab{}; }; } // namespace psr diff --git a/lib/Controller/AnalysisController.cpp b/lib/Controller/AnalysisController.cpp index c3ad51db1b..d54004559e 100644 --- a/lib/Controller/AnalysisController.cpp +++ b/lib/Controller/AnalysisController.cpp @@ -200,15 +200,7 @@ void AnalysisController::emitRequestedHelperAnalysisResults() { if (EmitterOptions & AnalysisControllerEmitterOptions::EmitStatisticsAsText) { - llvm::outs() << "Module " << IRDB.getModule()->getName() << ":\n"; - llvm::outs() << "> LLVM IR instructions:\t" << IRDB.getNumInstructions() - << "\n"; - llvm::outs() << "> Functions:\t\t" << IRDB.getModule()->size() << "\n"; - llvm::outs() << "> Global variables:\t" << IRDB.getModule()->global_size() - << "\n"; - llvm::outs() << "> Alloca instructions:\t" - << Stats.getAllocaInstructions().size() << "\n"; - llvm::outs() << "> Call Sites:\t\t" << Stats.getFunctioncalls() << "\n"; + llvm::outs() << Stats << '\n'; } if (EmitterOptions & From b5a770405a0fe36b113b2fa0609352caef6d6b6d Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Tue, 30 May 2023 09:04:00 +0200 Subject: [PATCH 12/14] Fix crash in LCA --- include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h b/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h index 7d07cc5fae..5151556a21 100644 --- a/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h @@ -425,6 +425,12 @@ ConstantEdgeFunction::join(EdgeFunctionRef This, if (auto Default = defaultJoinOrNull(This, OtherFunction)) { return Default; } + + if (llvm::isa>(OtherFunction)) { + // Prevent endless recursion + return AllBottom{}; + } + if (!OtherFunction.isConstant()) { // do not know how to join; hence ask other function to decide on this return OtherFunction.joinWith(This); From fa32d2c386c02466f3009de3a587e60fe44184e7 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sat, 3 Jun 2023 13:53:59 +0200 Subject: [PATCH 13/14] minor --- include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h | 3 +-- include/phasar/Utils/ChronoUtils.h | 4 ++++ include/phasar/Utils/DefaultValue.h | 3 ++- lib/Controller/AnalysisController.cpp | 1 - lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp | 4 ++-- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h b/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h index e4800cee85..c3abcad87d 100644 --- a/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h +++ b/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h @@ -22,12 +22,11 @@ #include "llvm/IR/Instruction.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/Support/MemoryBufferRef.h" #include "llvm/Support/raw_ostream.h" #include -#include - namespace psr { class LLVMProjectIRDB; diff --git a/include/phasar/Utils/ChronoUtils.h b/include/phasar/Utils/ChronoUtils.h index 2676c2cde0..d6acbf7184 100644 --- a/include/phasar/Utils/ChronoUtils.h +++ b/include/phasar/Utils/ChronoUtils.h @@ -17,6 +17,10 @@ namespace psr { +/// Simple struct that allows formatting of time-durations as +/// hours:minutes:seconds.microseconds. +/// +/// \remark This feature may come into C++23, so until then, use this one. struct hms { // NOLINT std::chrono::hours Hours{}; std::chrono::minutes Minutes{}; diff --git a/include/phasar/Utils/DefaultValue.h b/include/phasar/Utils/DefaultValue.h index c7525d32e4..ad2afaf32c 100644 --- a/include/phasar/Utils/DefaultValue.h +++ b/include/phasar/Utils/DefaultValue.h @@ -13,9 +13,10 @@ #include "phasar/Utils/ByRef.h" #include + namespace psr { -/// Gets a (cached) reference to the default-constructed value of type T. If T +/// Gets a (cached) reference to the default-constructed value of type T. If T /// is small and trivially default constructible, creates a temporary instead. /// Useful for getters that return ByConstRef but need to handle the /// non-existing-T case diff --git a/lib/Controller/AnalysisController.cpp b/lib/Controller/AnalysisController.cpp index f665d21f62..1341319a08 100644 --- a/lib/Controller/AnalysisController.cpp +++ b/lib/Controller/AnalysisController.cpp @@ -9,7 +9,6 @@ #include "phasar/Controller/AnalysisController.h" -#include "phasar//Utils/NlohmannLogging.h" #include "phasar/AnalysisStrategy/Strategies.h" #include "phasar/Controller/AnalysisControllerEmitterOptions.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" diff --git a/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp b/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp index 9f4105a7df..c498c2c918 100644 --- a/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp +++ b/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp @@ -115,8 +115,8 @@ LLVMProjectIRDB::LLVMProjectIRDB(llvm::MemoryBufferRef Buf) { Diag.print(nullptr, llvm::errs()); return; } - /* Crash in presence of llvm-3.9.1 module (segfault) */ - if (M == nullptr || llvm::verifyModule(*M, &llvm::errs(), &BrokenDebugInfo)) { + + if (llvm::verifyModule(*M, &llvm::errs(), &BrokenDebugInfo)) { PHASAR_LOG_LEVEL(ERROR, Buf.getBufferIdentifier() << " could not be parsed correctly!"); return; From e85b91e91cb5284e3ea72d22ceadadf49b6c8233 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Thu, 8 Jun 2023 12:30:38 +0200 Subject: [PATCH 14/14] Make myphasartool link properly with BUILD_SHARED_LIBS --- tools/example-tool/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/example-tool/CMakeLists.txt b/tools/example-tool/CMakeLists.txt index aab2a9a7d6..c5aa75c2ac 100644 --- a/tools/example-tool/CMakeLists.txt +++ b/tools/example-tool/CMakeLists.txt @@ -14,6 +14,7 @@ endif() target_link_libraries(myphasartool LINK_PUBLIC phasar + LLVM LINK_PRIVATE ${PHASAR_STD_FILESYSTEM} )