// \file Main.cpp // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/Error.h" #include "llvm/Support/raw_os_ostream.h" #include "revng/Model/LoadModelPass.h" #include "revng/Pipeline/AllRegistries.h" #include "revng/Pipeline/ContainerSet.h" #include "revng/Pipeline/CopyPipe.h" #include "revng/Pipeline/GenericLLVMPipe.h" #include "revng/Pipeline/LLVMContainerFactory.h" #include "revng/Pipeline/LLVMKind.h" #include "revng/Pipeline/Loader.h" #include "revng/Pipeline/Runner.h" #include "revng/Pipeline/Target.h" #include "revng/Pipes/ModelGlobal.h" #include "revng/Pipes/PipelineManager.h" #include "revng/Pipes/ToolCLOptions.h" #include "revng/Support/InitRevng.h" #include "revng/TupleTree/TupleTreeDiff.h" using std::string; using namespace llvm; using namespace llvm::cl; using namespace pipeline; using namespace ::revng::pipes; using namespace revng; static cl::list ContainerOverrides("i", desc("Load the target file in the " "target container at the " "target step"), cat(MainCategory)); static OutputPathOpt SaveModel("save-model", desc("Save the model at the end of the run"), cat(MainCategory)); static opt ApplyModelDiff("apply-model-diff", desc("Apply model diff"), cat(MainCategory), init("")); static opt ProduceAllPossibleTargets("produce-all", desc("Try producing all possible " "targets"), cat(MainCategory), init(false)); static opt ProduceAllPossibleTargetsSingle("produce-all-single", desc("Try producing all " "possible " "targets one element at " "the time"), cat(MainCategory), init(false)); static opt InvalidateAll("invalidate-all", desc("Try invalidating all possible " "targets after producing them. Used for " "debug purposes"), cat(MainCategory), init(false)); static opt DumpPipeline("d", desc("Dump built pipeline, but dont run it"), cat(MainCategory)); static cl::list StoresOverrides("o", desc("Store the target container at " "the " "target step in the target file"), cat(MainCategory)); static cl::list Produce("produce", desc("comma separated list of targets to be " "produced in one sweep."), cat(MainCategory)); static cl::list Analyze("analyze", desc("analyses to be performed."), cat(MainCategory)); static opt PrintBuildableTargets("targets", desc("Prints the target that can be " "produced from the current status " "and exit"), cat(MainCategory)); static alias A2("t", desc("Alias for --targets"), aliasopt(PrintBuildableTargets), cat(MainCategory)); static ToolCLOptions BaseOptions(MainCategory); static ExitOnError AbortOnError; static Runner::State parseProductionRequest(Runner &Pipeline, llvm::ArrayRef Targets) { Runner::State ToProduce; const auto &Registry = Pipeline.getKindsRegistry(); for (const auto &Target : Targets) { auto &&[StepName, Rest] = Target.split("/"); auto &Step = ToProduce[StepName]; AbortOnError(parseTarget(Pipeline.getContext(), Step, Rest, Registry)); } return ToProduce; } static void runAnalysis(Runner &Pipeline, llvm::StringRef Target) { const auto &Registry = Pipeline.getKindsRegistry(); auto &&[Step, Rest] = Target.split("/"); auto &&[AnalysisName, Rest2] = Rest.split("/"); ContainerToTargetsMap ToProduce; TargetInStepSet Map; AbortOnError(parseTarget(Pipeline.getContext(), ToProduce, Rest2, Registry)); AbortOnError(Pipeline.runAnalysis(AnalysisName, Step, ToProduce, Map)); } static void runPipeline(Runner &Pipeline) { // First run the requested analyses { Task T(Analyze.size(), "revng-pipeline analyses"); for (llvm::StringRef Entry : Analyze) { T.advance(Entry, true); runAnalysis(Pipeline, Entry); } } // Then produce the requested targets Task T(Produce.size(), "revng-pipeline produce"); for (llvm::StringRef Entry : Produce) { T.advance(Entry, true); llvm::SmallVector Targets; Entry.split(Targets, ","); AbortOnError(Pipeline.run(parseProductionRequest(Pipeline, Targets))); } } int main(int argc, char *argv[]) { revng::InitRevng X(argc, argv, "", { &MainCategory }); Registry::runAllInitializationRoutines(); auto Manager = AbortOnError(BaseOptions.makeManager()); for (const auto &Override : ContainerOverrides) AbortOnError(Manager.overrideContainer(Override)); if (DumpPipeline) { Manager.dump(); return EXIT_SUCCESS; } if (PrintBuildableTargets) { llvm::raw_os_ostream OS(dbg); Manager.writeAllPossibleTargets(OS); return EXIT_SUCCESS; } if (not ApplyModelDiff.empty()) { using Type = TupleTreeDiff; auto Diff = AbortOnError(fromFileOrSTDIN(ApplyModelDiff)); auto &Runner = Manager.getRunner(); TargetInStepSet Map; GlobalTupleTreeDiff GlobalDiff(std::move(Diff), ModelGlobalName); AbortOnError(Runner.apply(GlobalDiff, Map)); } runPipeline(Manager.getRunner()); if (ProduceAllPossibleTargets) AbortOnError(Manager.produceAllPossibleTargets()); else if (ProduceAllPossibleTargetsSingle) AbortOnError(Manager.produceAllPossibleSingleTargets()); if (InvalidateAll) { AbortOnError(Manager.invalidateAllPossibleTargets()); } AbortOnError(Manager.store(StoresOverrides)); AbortOnError(Manager.store()); if (SaveModel.hasValue()) { auto Context = Manager.context(); const auto &ModelName = revng::ModelGlobalName; auto FinalModel = AbortOnError(Context.getGlobal(ModelName)); AbortOnError(FinalModel->store(*SaveModel)); } return EXIT_SUCCESS; }