//===--- PassPipeline.h -----------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// /// /// \file /// /// This file defines the SILPassPipelinePlan and SILPassPipeline /// classes. These are higher level representations of sequences of SILPasses /// and the run behavior of these sequences (i.e. run one, until fixed point, /// etc). This makes it easy to serialize and deserialize pipelines without work /// on the part of the user. Eventually this will be paired with a gyb based /// representation of Passes.def that will able to be used to generate a python /// based script builder. /// //===----------------------------------------------------------------------===// #ifndef SWIFT_SILOPTIMIZER_PASSMANAGER_PASSPIPELINE_H #define SWIFT_SILOPTIMIZER_PASSMANAGER_PASSPIPELINE_H #include "swift/Basic/LLVM.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "llvm/ADT/Hashing.h" #include namespace swift { class SILPassPipelinePlan; struct SILPassPipeline final { unsigned ID; StringRef Name; unsigned KindOffset; bool isFunctionPassPipeline; friend bool operator==(const SILPassPipeline &lhs, const SILPassPipeline &rhs) { return lhs.ID == rhs.ID && lhs.Name == rhs.Name && lhs.KindOffset == rhs.KindOffset; } friend bool operator!=(const SILPassPipeline &lhs, const SILPassPipeline &rhs) { return !(lhs == rhs); } friend llvm::hash_code hash_value(const SILPassPipeline &pipeline) { return llvm::hash_combine(pipeline.ID, pipeline.Name, pipeline.KindOffset); } }; enum class PassPipelineKind { #define PASSPIPELINE(NAME, DESCRIPTION) NAME, #include "swift/SILOptimizer/PassManager/PassPipeline.def" }; class SILPassPipelinePlan final { const SILOptions &Options; std::vector Kinds; std::vector PipelineStages; public: SILPassPipelinePlan(const SILOptions &Options) : Options(Options), Kinds(), PipelineStages() {} ~SILPassPipelinePlan() = default; SILPassPipelinePlan(const SILPassPipelinePlan &) = default; const SILOptions &getOptions() const { return Options; } // Each pass gets its own add-function. #define PASS(ID, TAG, NAME) \ void add##ID() { \ assert(!PipelineStages.empty() && "startPipeline before adding passes."); \ Kinds.push_back(PassKind::ID); \ } #include "swift/SILOptimizer/PassManager/Passes.def" void addPasses(ArrayRef PassKinds); #define PASSPIPELINE(NAME, DESCRIPTION) \ static SILPassPipelinePlan get##NAME##PassPipeline(const SILOptions &Options); #include "swift/SILOptimizer/PassManager/PassPipeline.def" static SILPassPipelinePlan getPassPipelineForKinds(const SILOptions &Options, ArrayRef Kinds); static SILPassPipelinePlan getPassPipelineFromFile(const SILOptions &Options, StringRef Filename); /// Our general format is as follows: /// /// [ /// [ /// "PASS_MANAGER_ID", /// "one_iteration"|"until_fix_point", /// "PASS1", "PASS2", ... /// ], /// ... /// ] void dump(); void print(llvm::raw_ostream &os); void startPipeline(StringRef Name = "", bool isFunctionPassPipeline = false); using PipelineKindIterator = decltype(Kinds)::const_iterator; using PipelineKindRange = iterator_range; iterator_range getPipelinePasses(const SILPassPipeline &P) const; using PipelineIterator = decltype(PipelineStages)::const_iterator; using PipelineRange = iterator_range; PipelineRange getPipelines() const { return {PipelineStages.begin(), PipelineStages.end()}; } friend bool operator==(const SILPassPipelinePlan &lhs, const SILPassPipelinePlan &rhs) { // FIXME: Comparing the SILOptions by identity should work in practice, but // we don't currently prevent them from being copied. We should consider // either making them move-only, or properly implementing == for them. return &lhs.Options == &rhs.Options && lhs.Kinds == rhs.Kinds && lhs.PipelineStages == rhs.PipelineStages; } friend bool operator!=(const SILPassPipelinePlan &lhs, const SILPassPipelinePlan &rhs) { return !(lhs == rhs); } friend llvm::hash_code hash_value(const SILPassPipelinePlan &plan) { using namespace llvm; auto &kinds = plan.Kinds; auto &stages = plan.PipelineStages; return hash_combine(&plan.Options, hash_combine_range(kinds.begin(), kinds.end()), hash_combine_range(stages.begin(), stages.end())); } }; inline void SILPassPipelinePlan:: startPipeline(StringRef Name, bool isFunctionPassPipeline) { PipelineStages.push_back(SILPassPipeline{ unsigned(PipelineStages.size()), Name, unsigned(Kinds.size()), isFunctionPassPipeline}); } inline SILPassPipelinePlan::PipelineKindRange SILPassPipelinePlan::getPipelinePasses(const SILPassPipeline &P) const { unsigned ID = P.ID; assert(PipelineStages.size() > ID && "Pipeline with ID greater than the " "size of its container?!"); // In this case, we are the last pipeline. Return end and the kind offset. if ((PipelineStages.size() - 1) == ID) { return {std::next(Kinds.begin(), P.KindOffset), Kinds.end()}; } // Otherwise, end is the beginning of the next PipelineStage. return {std::next(Kinds.begin(), P.KindOffset), std::next(Kinds.begin(), PipelineStages[ID + 1].KindOffset)}; } } // end namespace swift #endif