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); 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/DataFlow/IfdsIde/SolverResults.h b/include/phasar/DataFlow/IfdsIde/SolverResults.h index 6a5671a50e..67d855deaa 100644 --- a/include/phasar/DataFlow/IfdsIde/SolverResults.h +++ b/include/phasar/DataFlow/IfdsIde/SolverResults.h @@ -95,7 +95,7 @@ class SolverResultsBase { llvm::Instruction>, std::unordered_map> resultsAtInLLVMSSA(ByConstRef Stmt, bool AllowOverapproximation = false, - bool StripZero = false); + bool StripZero = false) const; /// Returns the L-type result at the given statement for the given data-flow /// fact while respecting LLVM's SSA semantics. @@ -118,7 +118,7 @@ class SolverResultsBase { llvm::Instruction>, l_t> resultAtInLLVMSSA(ByConstRef Stmt, d_t Value, - bool AllowOverapproximation = false); + bool AllowOverapproximation = false) const; [[nodiscard]] std::vector::Cell> getAllResultEntries() const { @@ -129,7 +129,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; @@ -179,15 +179,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); @@ -206,12 +202,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; }; @@ -229,16 +225,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/PhasarLLVM/DB/LLVMProjectIRDB.h b/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h index d1b1789d26..c3abcad87d 100644 --- a/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h +++ b/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h @@ -22,6 +22,7 @@ #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 @@ -48,10 +49,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/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h index 0e334cb336..d789958cca 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h @@ -24,7 +24,7 @@ namespace psr::detail { template template auto SolverResultsBase::resultsAtInLLVMSSA( - ByConstRef Stmt, bool AllowOverapproximation, bool StripZero) -> + ByConstRef Stmt, bool AllowOverapproximation, bool StripZero) const -> typename std::enable_if_t< std::is_same_v>, llvm::Instruction>, @@ -96,7 +96,7 @@ auto SolverResultsBase::resultsAtInLLVMSSA( template template auto SolverResultsBase::resultAtInLLVMSSA( - ByConstRef Stmt, d_t Value, bool AllowOverapproximation) -> + ByConstRef Stmt, d_t Value, bool AllowOverapproximation) const -> typename std::enable_if_t< std::is_same_v>, llvm::Instruction>, diff --git a/include/phasar/Utils/ChronoUtils.h b/include/phasar/Utils/ChronoUtils.h new file mode 100644 index 0000000000..d6acbf7184 --- /dev/null +++ b/include/phasar/Utils/ChronoUtils.h @@ -0,0 +1,55 @@ +/****************************************************************************** + * 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 { + +/// 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{}; + 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/include/phasar/Utils/DefaultValue.h b/include/phasar/Utils/DefaultValue.h new file mode 100644 index 0000000000..ad2afaf32c --- /dev/null +++ b/include/phasar/Utils/DefaultValue.h @@ -0,0 +1,45 @@ +/****************************************************************************** + * 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/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 6b5511f64e..24ac50ac05 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 @@ -29,62 +33,54 @@ 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) { // 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(); } + 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. @@ -97,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); @@ -108,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) { @@ -119,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()) { @@ -152,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)) { @@ -162,80 +151,92 @@ 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. + return Tab[std::move(RowKey)][std::move(ColumnKey)]; } - [[nodiscard]] V &get(R RowKey, C ColumnKey) { - // Returns the value corresponding to the given row and column keys, or null + [[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. - return Tab[RowKey][ColumnKey]; + 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) { + 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. return Tab[RowKey]; } - [[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); + [[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 Result; + return It->second; } - [[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; } - [[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) { - return Lhs.table == Rhs.table; - } - - friend bool operator<(const Table &Lhs, const Table &Rhs) { - 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"; @@ -243,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 8406720ef4..1341319a08 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 & diff --git a/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp b/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp index d06b52acc0..c498c2c918 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; + } + + if (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()); 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()); +} 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} )