Files
revng-revng/include/revng/Pipes/PipelineManager.h
2025-04-30 15:08:45 +02:00

215 lines
8.3 KiB
C++

#pragma once
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include <string>
#include <vector>
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
#include "revng/Pipeline/Context.h"
#include "revng/Pipeline/Runner.h"
#include "revng/Pipes/ModelGlobal.h"
#include "revng/Storage/Path.h"
#include "revng/Storage/StorageClient.h"
namespace revng::pipes {
/// This is a "God Object" that can be used when there will be exactly one
/// Pipeline spawned by this process.
///
/// It will care of all configurations including llvm ones and provide a runner
/// in a usable state.
class PipelineManager {
private:
using Container = pipeline::ContainerSet::value_type;
explicit PipelineManager(llvm::ArrayRef<std::string> EnablingFlags,
std::unique_ptr<revng::StorageClient> &&Client);
std::unique_ptr<revng::StorageClient> StorageClient;
revng::DirectoryPath ExecutionDirectory;
/// The various member here MUST be unique_ptr to ensure that the various
/// pointer that go from one to the other are stable, Since there a create
/// method that returns a expected<PipelineManager>, this is the only way to
/// ensure this is correct.
std::unique_ptr<llvm::LLVMContext> LLVMContext;
std::unique_ptr<pipeline::Context> PipelineContext;
std::unique_ptr<pipeline::Loader> Loader;
std::unique_ptr<pipeline::Runner> Runner;
pipeline::Runner::State CurrentState;
std::map<const pipeline::ContainerSet::value_type *,
const pipeline::TargetsList *>
ContainerToEnumeration;
std::string Description;
public:
PipelineManager(PipelineManager &&Other) = default;
PipelineManager &operator=(PipelineManager &&Other) = default;
PipelineManager &operator=(const PipelineManager &Other) = delete;
PipelineManager(const PipelineManager &Other) = delete;
~PipelineManager() = default;
const pipeline::Kind *getKind(llvm::StringRef Name) const {
return Runner->getKindsRegistry().find(Name);
}
/// Tries to set up a PipelineManager with the provided files pipelines,
/// enabling flags loaded from the ExecutionDirectory. If anything is invalid
/// a Error is returned instead.
static llvm::Expected<PipelineManager>
create(llvm::ArrayRef<std::string> PipelinePath,
llvm::ArrayRef<std::string> EnablingFlags,
llvm::StringRef ExecutionDirectory);
/// Exactly like create except the pipeline are not provided as paths but
/// directly as yaml file buffer in memory.
static llvm::Expected<PipelineManager>
createFromMemory(llvm::ArrayRef<std::string> InMemoryPipeline,
llvm::ArrayRef<std::string> EnablingFlags,
llvm::StringRef ExecutionDirectory);
// This works exactly like the one above, but uses the provided StorageClient
// rather than parsing ExecutionDirectory
static llvm::Expected<PipelineManager>
createFromMemory(llvm::ArrayRef<std::string> InMemoryPipeline,
llvm::ArrayRef<std::string> EnablingFlags,
std::unique_ptr<revng::StorageClient> &&Client);
/// Entirelly replaces the container indicated by the mapping with the file
/// indicated by the mapping
llvm::Error overrideContainer(pipeline::PipelineFileMapping Mapping);
/// The same as the previous overload except the mapping is provided as a
/// triple to be parsed is the usual way.
llvm::Error overrideContainer(llvm::StringRef PipelineFileMapping);
/// Stores the content of the container indicated by the mapping at the path
/// indicated by the mapping, and nothing else.
llvm::Error store(const pipeline::PipelineFileMapping &StoresOverride);
/// Builds FileMapping out of each provided string and the invoke store on
/// each of them.
llvm::Error store(llvm::ArrayRef<std::string> StoresOverrides);
/// Triggers the full serialization of every step and every container to the
/// Execution directory.
llvm::Error store();
/// Trigger the serialization of a single Step to the specified DirPath or
/// the Execution directory if omitted.
llvm::Error storeStepToDisk(llvm::StringRef StepName);
const pipeline::Step::AnalysisValueType &
getAnalysis(const pipeline::AnalysisReference &Reference) const;
llvm::Expected<pipeline::TargetInStepSet>
deserializeContainer(pipeline::Step &Step,
llvm::StringRef ContainerName,
const llvm::MemoryBuffer &Buffer);
const pipeline::Context &context() const { return *PipelineContext; }
pipeline::Context &context() { return *PipelineContext; }
/// recalculates the current available targetsd and keeps overship of the
/// computer info
void recalculateCurrentState();
/// recalculates the cache for fast lookups
void recalculateCache();
/// like recalculate by the ownerhip is maintained by State
void getAllPossibleTargets(pipeline::Runner::State &State,
bool ExpandTargets = true) const;
/// like recalculate by the ownerhip is maintained by State
void getCurrentState(pipeline::Runner::State &State) const;
/// returns a reference to the internal Runner::State populated by recalculate
/// memethods.
const pipeline::Runner::State &getLastState() const { return CurrentState; }
/// A helper function used to produce all possible targets. It is used for
/// debug purposes to see if any particular target crashes.
llvm::Error produceAllPossibleTargets() {
return produceAllPossibleTargets(false);
}
llvm::Error produceAllPossibleSingleTargets() {
return produceAllPossibleTargets(true);
}
llvm::Expected<pipeline::TargetInStepSet> invalidateAllPossibleTargets();
llvm::Expected<pipeline::TargetInStepSet>
invalidateFromDiff(const llvm::StringRef Name,
const pipeline::GlobalTupleTreeDiff &Diff);
/// returns the cached list of targets that are known to be available to be
/// produced in a container
const pipeline::TargetsList *
getTargetsAvailableFor(const Container &TheContainer) const {
if (auto Iter = ContainerToEnumeration.find(&TheContainer);
Iter == ContainerToEnumeration.end())
return nullptr;
else
return Iter->second;
}
void dump() const { Runner->dump(); }
const pipeline::Runner &getRunner() const { return *Runner; }
pipeline::Runner &getRunner() { return *Runner; }
llvm::Error materializeTargets(const llvm::StringRef StepName,
const pipeline::ContainerToTargetsMap &Map);
llvm::Expected<std::unique_ptr<pipeline::ContainerBase>>
produceTargets(const llvm::StringRef StepName,
const Container &TheContainer,
const pipeline::TargetsList &List);
llvm::Expected<pipeline::DiffMap>
runAnalyses(const pipeline::AnalysesList &List,
pipeline::TargetInStepSet &Map,
const llvm::StringMap<std::string> &Options = {},
llvm::raw_ostream *DiagnosticLog = nullptr);
llvm::Expected<pipeline::DiffMap>
runAnalysis(llvm::StringRef AnalysisName,
llvm::StringRef StepName,
const pipeline::ContainerToTargetsMap &Targets,
pipeline::TargetInStepSet &Map,
const llvm::StringMap<std::string> &Options = {},
llvm::raw_ostream *DiagnosticLog = nullptr);
const pipeline::Loader &getLoader() const { return *Loader; }
/// recalculates all possible targets and keeps overship of the computed info
void recalculateAllPossibleTargets(bool ExpandTargets = true);
/// prints to the provided raw_ostream all possible targets that can
/// be produced by the pipeline in the current state
void writeAllPossibleTargets(llvm::raw_ostream &OS) const;
const revng::DirectoryPath &executionDirectory() const {
return ExecutionDirectory;
}
const llvm::StringRef getPipelineDescription() const { return Description; }
llvm::Error setStorageCredentials(llvm::StringRef Credentials);
private:
llvm::Error produceAllPossibleTargets(bool ExpandTargets);
llvm::Error computeDescription();
llvm::Error setUpPipeline(llvm::ArrayRef<std::string> TextPipelines);
/// removes all the files that can be re-created by the pipeline
llvm::Error purge(const revng::DirectoryPath &ExecutionDirectory);
llvm::Error
checkComponentsVersion(const revng::DirectoryPath &ExecutionDirectory);
};
} // namespace revng::pipes