Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:44:26

0001 //===- PassManager.h --------------------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // Registers and executes the Sandbox IR passes.
0010 //
0011 // The pass manager contains an ordered sequence of passes that it runs in
0012 // order. The passes are owned by the PassRegistry, not by the PassManager.
0013 //
0014 // Note that in this design a pass manager is also a pass. So a pass manager
0015 // runs when it is it's turn to run in its parent pass-manager pass pipeline.
0016 //
0017 
0018 #ifndef LLVM_SANDBOXIR_PASSMANAGER_H
0019 #define LLVM_SANDBOXIR_PASSMANAGER_H
0020 
0021 #include <memory>
0022 
0023 #include "llvm/ADT/DenseMap.h"
0024 #include "llvm/ADT/STLExtras.h"
0025 #include "llvm/SandboxIR/Pass.h"
0026 #include "llvm/Support/Debug.h"
0027 
0028 namespace llvm::sandboxir {
0029 
0030 class Value;
0031 
0032 /// Base class.
0033 template <typename ParentPass, typename ContainedPass>
0034 class PassManager : public ParentPass {
0035 public:
0036   // CreatePassFunc(StringRef PassName, StringRef PassArgs).
0037   using CreatePassFunc =
0038       std::function<std::unique_ptr<ContainedPass>(StringRef, StringRef)>;
0039 
0040 protected:
0041   /// The list of passes that this pass manager will run.
0042   SmallVector<std::unique_ptr<ContainedPass>> Passes;
0043 
0044   PassManager(StringRef Name) : ParentPass(Name) {}
0045   PassManager(StringRef Name, StringRef Pipeline, CreatePassFunc CreatePass)
0046       : ParentPass(Name) {
0047     setPassPipeline(Pipeline, CreatePass);
0048   }
0049   PassManager(const PassManager &) = delete;
0050   PassManager(PassManager &&) = default;
0051   virtual ~PassManager() = default;
0052   PassManager &operator=(const PassManager &) = delete;
0053 
0054 public:
0055   /// Adds \p Pass to the pass pipeline.
0056   void addPass(std::unique_ptr<ContainedPass> Pass) {
0057     // TODO: Check that Pass's class type works with this PassManager type.
0058     Passes.push_back(std::move(Pass));
0059   }
0060 
0061   /// Parses \p Pipeline as a comma-separated sequence of pass names and sets
0062   /// the pass pipeline, using \p CreatePass to instantiate passes by name.
0063   ///
0064   /// Passes can have arguments, for example:
0065   ///   "pass1<arg1,arg2>,pass2,pass3<arg3,arg4>"
0066   ///
0067   /// The arguments between angle brackets are treated as a mostly opaque string
0068   /// and each pass is responsible for parsing its arguments. The exception to
0069   /// this are nested angle brackets, which must match pair-wise to allow
0070   /// arguments to contain nested pipelines, like:
0071   ///
0072   ///   "pass1<subpass1,subpass2<arg1,arg2>,subpass3>"
0073   ///
0074   /// An empty args string is treated the same as no args, so "pass" and
0075   /// "pass<>" are equivalent.
0076   void setPassPipeline(StringRef Pipeline, CreatePassFunc CreatePass) {
0077     static constexpr const char EndToken = '\0';
0078     static constexpr const char BeginArgsToken = '<';
0079     static constexpr const char EndArgsToken = '>';
0080     static constexpr const char PassDelimToken = ',';
0081 
0082     assert(Passes.empty() &&
0083            "setPassPipeline called on a non-empty sandboxir::PassManager");
0084 
0085     // Accept an empty pipeline as a special case. This can be useful, for
0086     // example, to test conversion to SandboxIR without running any passes on
0087     // it.
0088     if (Pipeline.empty())
0089       return;
0090 
0091     // Add EndToken to the end to ease parsing.
0092     std::string PipelineStr = std::string(Pipeline) + EndToken;
0093     Pipeline = StringRef(PipelineStr);
0094 
0095     auto AddPass = [this, CreatePass](StringRef PassName, StringRef PassArgs) {
0096       if (PassName.empty()) {
0097         errs() << "Found empty pass name.\n";
0098         exit(1);
0099       }
0100       // Get the pass that corresponds to PassName and add it to the pass
0101       // manager.
0102       auto Pass = CreatePass(PassName, PassArgs);
0103       if (Pass == nullptr) {
0104         errs() << "Pass '" << PassName << "' not registered!\n";
0105         exit(1);
0106       }
0107       addPass(std::move(Pass));
0108     };
0109 
0110     enum class State {
0111       ScanName,  // reading a pass name
0112       ScanArgs,  // reading a list of args
0113       ArgsEnded, // read the last '>' in an args list, must read delimiter next
0114     } CurrentState = State::ScanName;
0115     int PassBeginIdx = 0;
0116     int ArgsBeginIdx;
0117     StringRef PassName;
0118     int NestedArgs = 0;
0119     for (auto [Idx, C] : enumerate(Pipeline)) {
0120       switch (CurrentState) {
0121       case State::ScanName:
0122         if (C == BeginArgsToken) {
0123           // Save pass name for later and begin scanning args.
0124           PassName = Pipeline.slice(PassBeginIdx, Idx);
0125           ArgsBeginIdx = Idx + 1;
0126           ++NestedArgs;
0127           CurrentState = State::ScanArgs;
0128           break;
0129         }
0130         if (C == EndArgsToken) {
0131           errs() << "Unexpected '>' in pass pipeline.\n";
0132           exit(1);
0133         }
0134         if (C == EndToken || C == PassDelimToken) {
0135           // Delimiter found, add the pass (with empty args), stay in the
0136           // ScanName state.
0137           AddPass(Pipeline.slice(PassBeginIdx, Idx), StringRef());
0138           PassBeginIdx = Idx + 1;
0139         }
0140         break;
0141       case State::ScanArgs:
0142         // While scanning args, we only care about making sure nesting of angle
0143         // brackets is correct.
0144         if (C == BeginArgsToken) {
0145           ++NestedArgs;
0146           break;
0147         }
0148         if (C == EndArgsToken) {
0149           --NestedArgs;
0150           if (NestedArgs == 0) {
0151             // Done scanning args.
0152             AddPass(PassName, Pipeline.slice(ArgsBeginIdx, Idx));
0153             CurrentState = State::ArgsEnded;
0154           } else if (NestedArgs < 0) {
0155             errs() << "Unexpected '>' in pass pipeline.\n";
0156             exit(1);
0157           }
0158           break;
0159         }
0160         if (C == EndToken) {
0161           errs() << "Missing '>' in pass pipeline. End-of-string reached while "
0162                     "reading arguments for pass '"
0163                  << PassName << "'.\n";
0164           exit(1);
0165         }
0166         break;
0167       case State::ArgsEnded:
0168         // Once we're done scanning args, only a delimiter is valid. This avoids
0169         // accepting strings like "foo<args><more-args>" or "foo<args>bar".
0170         if (C == EndToken || C == PassDelimToken) {
0171           PassBeginIdx = Idx + 1;
0172           CurrentState = State::ScanName;
0173         } else {
0174           errs() << "Expected delimiter or end-of-string after pass "
0175                     "arguments.\n";
0176           exit(1);
0177         }
0178         break;
0179       }
0180     }
0181   }
0182 
0183 #ifndef NDEBUG
0184   void print(raw_ostream &OS) const override {
0185     OS << this->getName();
0186     OS << "(";
0187     // TODO: This should call Pass->print(OS) because Pass may be a PM.
0188     interleave(Passes, OS, [&OS](auto &Pass) { OS << Pass->getName(); }, ",");
0189     OS << ")";
0190   }
0191   LLVM_DUMP_METHOD void dump() const override {
0192     print(dbgs());
0193     dbgs() << "\n";
0194   }
0195 #endif
0196   /// Similar to print() but prints one pass per line. Used for testing.
0197   void printPipeline(raw_ostream &OS) const override {
0198     OS << this->getName() << "\n";
0199     for (const auto &PassPtr : Passes)
0200       PassPtr->printPipeline(OS);
0201   }
0202 };
0203 
0204 class FunctionPassManager final
0205     : public PassManager<FunctionPass, FunctionPass> {
0206 public:
0207   FunctionPassManager(StringRef Name) : PassManager(Name) {}
0208   FunctionPassManager(StringRef Name, StringRef Pipeline,
0209                       CreatePassFunc CreatePass)
0210       : PassManager(Name, Pipeline, CreatePass) {}
0211   bool runOnFunction(Function &F, const Analyses &A) final;
0212 };
0213 
0214 class RegionPassManager final : public PassManager<RegionPass, RegionPass> {
0215 public:
0216   RegionPassManager(StringRef Name) : PassManager(Name) {}
0217   RegionPassManager(StringRef Name, StringRef Pipeline,
0218                     CreatePassFunc CreatePass)
0219       : PassManager(Name, Pipeline, CreatePass) {}
0220   bool runOnRegion(Region &R, const Analyses &A) final;
0221 };
0222 
0223 } // namespace llvm::sandboxir
0224 
0225 #endif // LLVM_SANDBOXIR_PASSMANAGER_H