================ @@ -0,0 +1,212 @@ +//===- AnalysisDriver.cpp -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/ScalableStaticAnalysisFramework/Core/WholeProgramAnalysis/AnalysisDriver.h" +#include "clang/ScalableStaticAnalysisFramework/Core/Support/ErrorBuilder.h" +#include "clang/ScalableStaticAnalysisFramework/Core/WholeProgramAnalysis/AnalysisRegistry.h" +#include "clang/ScalableStaticAnalysisFramework/Core/WholeProgramAnalysis/DerivedAnalysis.h" +#include "clang/ScalableStaticAnalysisFramework/Core/WholeProgramAnalysis/SummaryAnalysis.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" +#include <map> +#include <vector> + +using namespace clang; +using namespace ssaf; + +AnalysisDriver::AnalysisDriver(std::unique_ptr<LUSummary> LU) + : LU(std::move(LU)) {} + +llvm::Expected<std::vector<std::unique_ptr<AnalysisBase>>> +AnalysisDriver::toposort(llvm::ArrayRef<AnalysisName> Roots) { + struct Visitor { + enum class State { Unvisited, Visiting, Visited }; + + std::map<AnalysisName, State> Marks; + std::vector<AnalysisName> Path; + std::vector<std::unique_ptr<AnalysisBase>> Result; + + explicit Visitor(size_t N) { + Path.reserve(N); + Result.reserve(N); + } + + std::string formatCycle(const AnalysisName &CycleEntry) const { + auto CycleBegin = llvm::find(Path, CycleEntry); + std::string Cycle; + llvm::raw_string_ostream OS(Cycle); + llvm::interleave(llvm::make_range(CycleBegin, Path.end()), OS, " -> "); + OS << " -> " << CycleEntry; + return Cycle; + } + + llvm::Error visit(const AnalysisName &Name) { + auto [It, _] = Marks.emplace(Name, State::Unvisited); + + switch (It->second) { + case State::Visited: + return llvm::Error::success(); + + case State::Visiting: + return ErrorBuilder::create(std::errc::invalid_argument, + "cycle detected: {0}", formatCycle(Name)) + .build(); + + case State::Unvisited: { + It->second = State::Visiting; + Path.push_back(Name); + + llvm::Expected<std::unique_ptr<AnalysisBase>> V = + AnalysisRegistry::instantiate(Name); + if (!V) { + return V.takeError(); + } + + // Unwrap for convenience to avoid the noise of dereferencing an + // Expected on every subsequent access. + std::unique_ptr<AnalysisBase> Analysis = std::move(*V); + + for (const auto &Dep : Analysis->dependencyNames()) { + if (auto Err = visit(Dep)) { + return Err; + } + } + + // std::map iterators are not invalidated by insertions, so It remains + // valid after recursive visit() calls that insert new entries. + It->second = State::Visited; + Path.pop_back(); + Result.push_back(std::move(Analysis)); + + return llvm::Error::success(); + } + } + llvm_unreachable("unhandled State"); + } + }; + + Visitor V(Roots.size()); + for (const auto &Root : Roots) { + if (auto Err = V.visit(Root)) { + return std::move(Err); + } + } + return std::move(V.Result); +} + +llvm::Error AnalysisDriver::executeSummaryAnalysis(SummaryAnalysisBase &Summary, + WPASuite &Suite) const { + SummaryName SN = Summary.summaryName(); + auto DataIt = LU->Data.find(SN); + if (DataIt == LU->Data.end()) { + return ErrorBuilder::create(std::errc::invalid_argument, + "no data for analysis '{0}' in LUSummary", + Summary.analysisName()) + .build(); + } + + if (auto Err = Summary.initialize()) { + return Err; + } + + for (auto &[Id, EntitySummary] : DataIt->second) { + if (auto Err = Summary.add(Id, *EntitySummary)) { + return Err; + } + } + + if (auto Err = Summary.finalize()) { + return Err; + } + + return llvm::Error::success(); +} + +llvm::Error AnalysisDriver::executeDerivedAnalysis(DerivedAnalysisBase &Derived, + WPASuite &Suite) const { + std::map<AnalysisName, const AnalysisResult *> DepMap; + + for (const auto &DepName : Derived.dependencyNames()) { + auto It = Suite.Data.find(DepName); + if (It == Suite.Data.end()) { + ErrorBuilder::fatal("missing dependency '{0}' for analysis '{1}': " + "dependency graph is not topologically sorted", + DepName, Derived.analysisName()); + } + DepMap[DepName] = It->second.get(); + } + + if (auto Err = Derived.initialize(DepMap)) { + return Err; + } + + while (true) { + auto StepOrErr = Derived.step(); + if (!StepOrErr) { + return StepOrErr.takeError(); + } + if (!*StepOrErr) { + break; + } + } + + if (auto Err = Derived.finalize()) { + return Err; + } + + return llvm::Error::success(); +} + +llvm::Expected<WPASuite> AnalysisDriver::execute( + EntityIdTable IdTable, + llvm::ArrayRef<std::unique_ptr<AnalysisBase>> Sorted) const { + WPASuite Suite; + Suite.IdTable = std::move(IdTable); + + for (auto &Analysis : Sorted) { + switch (Analysis->TheKind) { + case AnalysisBase::Kind::Summary: { + SummaryAnalysisBase &SA = static_cast<SummaryAnalysisBase &>(*Analysis); + if (auto Err = executeSummaryAnalysis(SA, Suite)) { + return std::move(Err); + } + break; + } + case AnalysisBase::Kind::Derived: { + DerivedAnalysisBase &DA = static_cast<DerivedAnalysisBase &>(*Analysis); + if (auto Err = executeDerivedAnalysis(DA, Suite)) { + return std::move(Err); + } + break; + } + } + AnalysisName Name = Analysis->analysisName(); + Suite.Data.emplace(std::move(Name), std::move(*Analysis).result()); + } + + return Suite; ---------------- steakhal wrote:
We need this std-move to make gcc-7 happy. ```suggestion return std::move(Suite); ``` https://github.com/llvm/llvm-project/pull/186813 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
