#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include #include #include #include #include "llvm/ADT/ArrayRef.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/PassRegistry.h" #include "revng/ADT/Concepts.h" #include "revng/Pipeline/ContainerFactorySet.h" #include "revng/Pipeline/Contract.h" #include "revng/Pipeline/Step.h" #include "revng/Support/Debug.h" #include "revng/Support/Error.h" #include "revng/Support/ResourceFinder.h" namespace pipeline { class LLVMContainer; class LLVMPassWrapperBase { public: virtual ~LLVMPassWrapperBase() = default; virtual void registerPasses(llvm::legacy::PassManager &Manager) = 0; virtual const std::vector &getContract() const = 0; virtual std::unique_ptr clone() const = 0; virtual llvm::StringRef getName() const = 0; }; template concept LLVMPass = requires(T P) { { T::Name } -> convertible_to; { P.registerPasses(std::declval()) }; }; class PureLLVMPassWrapper : public LLVMPassWrapperBase { private: std::string PassName; public: PureLLVMPassWrapper(llvm::StringRef PassName) : PassName(PassName.str()) {} static bool passExists(llvm::StringRef PassName) { return llvm::PassRegistry::getPassRegistry()->getPassInfo(PassName); } static llvm::Expected> create(llvm::StringRef PassName) { if (not passExists(PassName)) return revng::createError("Could not load llvm pass " + PassName); return std::make_unique(PassName); } ~PureLLVMPassWrapper() override = default; void registerPasses(llvm::legacy::PassManager &Manager) override; const std::vector &getContract() const override { static const std::vector Empty{}; return Empty; } std::unique_ptr clone() const override; llvm::StringRef getName() const override { return PassName; } }; /// LLVM pipes are pipes composed of any number of llvm passes /// /// The contract is deduced by the used passes, and the passes are assembled /// into pass managers when needed. template class LLVMPassWrapper : public LLVMPassWrapperBase { public: using RegistrationFunctionType = void (*)(llvm::legacy::PassManager &); private: T PipePass; std::vector Contract; public: LLVMPassWrapper(T Pass) : PipePass(std::move(Pass)), Contract(this->PipePass.getContract()) {} LLVMPassWrapper(const LLVMPassWrapper &Other) = default; LLVMPassWrapper(LLVMPassWrapper &&Other) = default; template LLVMPassWrapper(ArgsT &&...Args) : PipePass(std::forward(Args)...), Contract(this->PipePass.getContract()) {} ~LLVMPassWrapper() override = default; public: llvm::StringRef getName() const override { return T ::Name; } public: void registerPasses(llvm::legacy::PassManager &Manager) override { PipePass.registerPasses(Manager); } const std::vector &getContract() const override { return Contract; } std::unique_ptr clone() const override { return std::make_unique(*this); } }; /// Implementation of the LLVM pipes to be instantiated for a particular LLVM /// container class GenericLLVMPipe { private: llvm::SmallVector, 4> Passes; public: static constexpr auto Name = "generic-llvm-pipe"; template explicit GenericLLVMPipe(T... Pass) { (addPass(std::move(Pass)), ...); } GenericLLVMPipe &operator=(const GenericLLVMPipe &Other) { if (this == &Other) return *this; llvm::SmallVector, 4> NewPasses; for (const auto &P : Other.Passes) NewPasses.push_back(P->clone()); Passes = std::move(NewPasses); return *this; } GenericLLVMPipe(const GenericLLVMPipe &Other) { for (const auto &P : Other.Passes) Passes.push_back(P->clone()); } GenericLLVMPipe &operator=(GenericLLVMPipe &&Other) = default; GenericLLVMPipe(GenericLLVMPipe &&Other) = default; ~GenericLLVMPipe() = default; std::vector getContract() const { std::vector Contract; for (const auto &Element : Passes) for (const auto &C : Element->getContract()) Contract.push_back(C); return Contract; } void run(ExecutionContext &, LLVMContainer &Container); void addPass(const PureLLVMPassWrapper &Pass) { Passes.emplace_back(Pass.clone()); } template void addPass(T Pass) { using Type = LLVMPassWrapper; auto Wrapper = std::make_unique(std::forward(Pass)); Passes.emplace_back(std::move(Wrapper)); } template void emplacePass(ArgsT &&...Args) { using Type = LLVMPassWrapper; auto Wrapper = std::make_unique(std::forward(Args)...); Passes.emplace_back(std::move(Wrapper)); } void addPass(std::unique_ptr Impl) { Passes.emplace_back(std::move(Impl)); } public: std::string getName() const { std::string Result = std::string(Name) + "("; const char *Prefix = ""; for (const auto &Pass : Passes) { Result += Prefix + Pass->getName().str(); Prefix = ", "; } Result += ")"; return Result; } template void dump(OStream &OS, size_t Indentation = 0) const { for (const auto &Pass : Passes) { indent(OS, Indentation); OS << Pass->getName().str() << "\n"; } } void dump() const debug_function { dump(dbg); } }; class O2Pipe { public: static constexpr auto Name = "o2"; std::vector getContract() const { return {}; } void registerPasses(llvm::legacy::PassManager &Manager); }; using LLVMPipe = GenericLLVMPipe; } // namespace pipeline