diff --git a/llvm/include/llvm/SandboxIR/Pass.h b/llvm/include/llvm/SandboxIR/Pass.h index 211f10f5d57c5..5ed9d7442ee70 100644 --- a/llvm/include/llvm/SandboxIR/Pass.h +++ b/llvm/include/llvm/SandboxIR/Pass.h @@ -43,7 +43,7 @@ class Pass { LLVM_DUMP_METHOD virtual void dump() const; #endif /// Similar to print() but adds a newline. Used for testing. - void printPipeline(raw_ostream &OS) const { OS << Name << "\n"; } + virtual void printPipeline(raw_ostream &OS) const { OS << Name << "\n"; } }; /// A pass that runs on a sandbox::Function. diff --git a/llvm/include/llvm/SandboxIR/PassManager.h b/llvm/include/llvm/SandboxIR/PassManager.h index 247c43615f576..e8221996bc8f0 100644 --- a/llvm/include/llvm/SandboxIR/PassManager.h +++ b/llvm/include/llvm/SandboxIR/PassManager.h @@ -32,11 +32,20 @@ class Value; /// Base class. template class PassManager : public ParentPass { +public: + // CreatePassFunc(StringRef PassName, StringRef PassArgs). + using CreatePassFunc = + std::function(StringRef, StringRef)>; + protected: /// The list of passes that this pass manager will run. SmallVector> Passes; PassManager(StringRef Name) : ParentPass(Name) {} + PassManager(StringRef Name, StringRef Pipeline, CreatePassFunc CreatePass) + : ParentPass(Name) { + setPassPipeline(Pipeline, CreatePass); + } PassManager(const PassManager &) = delete; PassManager(PassManager &&) = default; virtual ~PassManager() = default; @@ -49,41 +58,125 @@ class PassManager : public ParentPass { Passes.push_back(std::move(Pass)); } - using CreatePassFunc = - std::function(StringRef)>; - /// Parses \p Pipeline as a comma-separated sequence of pass names and sets /// the pass pipeline, using \p CreatePass to instantiate passes by name. /// - /// After calling this function, the PassManager contains only the specified - /// pipeline, any previously added passes are cleared. + /// Passes can have arguments, for example: + /// "pass1,pass2,pass3" + /// + /// The arguments between angle brackets are treated as a mostly opaque string + /// and each pass is responsible for parsing its arguments. The exception to + /// this are nested angle brackets, which must match pair-wise to allow + /// arguments to contain nested pipelines, like: + /// + /// "pass1,subpass3>" + /// + /// An empty args string is treated the same as no args, so "pass" and + /// "pass<>" are equivalent. void setPassPipeline(StringRef Pipeline, CreatePassFunc CreatePass) { static constexpr const char EndToken = '\0'; + static constexpr const char BeginArgsToken = '<'; + static constexpr const char EndArgsToken = '>'; static constexpr const char PassDelimToken = ','; assert(Passes.empty() && "setPassPipeline called on a non-empty sandboxir::PassManager"); + + // Accept an empty pipeline as a special case. This can be useful, for + // example, to test conversion to SandboxIR without running any passes on + // it. + if (Pipeline.empty()) + return; + // Add EndToken to the end to ease parsing. std::string PipelineStr = std::string(Pipeline) + EndToken; - int FlagBeginIdx = 0; - - for (auto [Idx, C] : enumerate(PipelineStr)) { - // Keep moving Idx until we find the end of the pass name. - bool FoundDelim = C == EndToken || C == PassDelimToken; - if (!FoundDelim) - continue; - unsigned Sz = Idx - FlagBeginIdx; - std::string PassName(&PipelineStr[FlagBeginIdx], Sz); - FlagBeginIdx = Idx + 1; + Pipeline = StringRef(PipelineStr); + auto AddPass = [this, CreatePass](StringRef PassName, StringRef PassArgs) { + if (PassName.empty()) { + errs() << "Found empty pass name.\n"; + exit(1); + } // Get the pass that corresponds to PassName and add it to the pass // manager. - auto Pass = CreatePass(PassName); + auto Pass = CreatePass(PassName, PassArgs); if (Pass == nullptr) { errs() << "Pass '" << PassName << "' not registered!\n"; exit(1); } addPass(std::move(Pass)); + }; + + enum class State { + ScanName, // reading a pass name + ScanArgs, // reading a list of args + ArgsEnded, // read the last '>' in an args list, must read delimiter next + } CurrentState = State::ScanName; + int PassBeginIdx = 0; + int ArgsBeginIdx; + StringRef PassName; + int NestedArgs = 0; + for (auto [Idx, C] : enumerate(Pipeline)) { + switch (CurrentState) { + case State::ScanName: + if (C == BeginArgsToken) { + // Save pass name for later and begin scanning args. + PassName = Pipeline.slice(PassBeginIdx, Idx); + ArgsBeginIdx = Idx + 1; + ++NestedArgs; + CurrentState = State::ScanArgs; + break; + } + if (C == EndArgsToken) { + errs() << "Unexpected '>' in pass pipeline.\n"; + exit(1); + } + if (C == EndToken || C == PassDelimToken) { + // Delimiter found, add the pass (with empty args), stay in the + // ScanName state. + AddPass(Pipeline.slice(PassBeginIdx, Idx), StringRef()); + PassBeginIdx = Idx + 1; + } + break; + case State::ScanArgs: + // While scanning args, we only care about making sure nesting of angle + // brackets is correct. + if (C == BeginArgsToken) { + ++NestedArgs; + break; + } + if (C == EndArgsToken) { + --NestedArgs; + if (NestedArgs == 0) { + // Done scanning args. + AddPass(PassName, Pipeline.slice(ArgsBeginIdx, Idx)); + CurrentState = State::ArgsEnded; + } else if (NestedArgs < 0) { + errs() << "Unexpected '>' in pass pipeline.\n"; + exit(1); + } + break; + } + if (C == EndToken) { + errs() << "Missing '>' in pass pipeline. End-of-string reached while " + "reading arguments for pass '" + << PassName << "'.\n"; + exit(1); + } + break; + case State::ArgsEnded: + // Once we're done scanning args, only a delimiter is valid. This avoids + // accepting strings like "foo" or "foobar". + if (C == EndToken || C == PassDelimToken) { + PassBeginIdx = Idx + 1; + CurrentState = State::ScanName; + } else { + errs() << "Expected delimiter or end-of-string after pass " + "arguments.\n"; + exit(1); + } + break; + } } } @@ -101,7 +194,7 @@ class PassManager : public ParentPass { } #endif /// Similar to print() but prints one pass per line. Used for testing. - void printPipeline(raw_ostream &OS) const { + void printPipeline(raw_ostream &OS) const override { OS << this->getName() << "\n"; for (const auto &PassPtr : Passes) PassPtr->printPipeline(OS); @@ -112,12 +205,18 @@ class FunctionPassManager final : public PassManager { public: FunctionPassManager(StringRef Name) : PassManager(Name) {} + FunctionPassManager(StringRef Name, StringRef Pipeline, + CreatePassFunc CreatePass) + : PassManager(Name, Pipeline, CreatePass) {} bool runOnFunction(Function &F) final; }; class RegionPassManager final : public PassManager { public: RegionPassManager(StringRef Name) : PassManager(Name) {} + RegionPassManager(StringRef Name, StringRef Pipeline, + CreatePassFunc CreatePass) + : PassManager(Name, Pipeline, CreatePass) {} bool runOnRegion(Region &R) final; }; diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.h index 02abdf0a1ef0d..5cd47efd6b346 100644 --- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.h +++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.h @@ -13,15 +13,15 @@ #define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_PASSES_BOTTOMUPVEC_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" #include "llvm/SandboxIR/Constant.h" #include "llvm/SandboxIR/Pass.h" #include "llvm/SandboxIR/PassManager.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Vectorize/SandboxVectorizer/Legality.h" namespace llvm::sandboxir { -class RegionPassManager; - class BottomUpVec final : public FunctionPass { bool Change = false; LegalityAnalysis Legality; @@ -32,8 +32,12 @@ class BottomUpVec final : public FunctionPass { RegionPassManager RPM; public: - BottomUpVec(); + BottomUpVec(StringRef Pipeline); bool runOnFunction(Function &F) final; + void printPipeline(raw_ostream &OS) const final { + OS << getName() << "\n"; + RPM.printPipeline(OS); + } }; } // namespace llvm::sandboxir diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Passes/PrintInstructionCount.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Passes/PrintInstructionCount.h new file mode 100644 index 0000000000000..9d88bc8280384 --- /dev/null +++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Passes/PrintInstructionCount.h @@ -0,0 +1,23 @@ +#ifndef LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_PASSES_PRINTINSTRUCTIONCOUNT_H +#define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_PASSES_PRINTINSTRUCTIONCOUNT_H + +#include "llvm/SandboxIR/Pass.h" +#include "llvm/SandboxIR/Region.h" + +namespace llvm::sandboxir { + +/// A Region pass that prints the instruction count for the region to stdout. +/// Used to test -sbvec-passes while we don't have any actual optimization +/// passes. +class PrintInstructionCount final : public RegionPass { +public: + PrintInstructionCount() : RegionPass("null") {} + bool runOnRegion(Region &R) final { + outs() << "InstructionCount: " << std::distance(R.begin(), R.end()) << "\n"; + return false; + } +}; + +} // namespace llvm::sandboxir + +#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_PASSES_PRINTINSTRUCTIONCOUNTPASS_H diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Passes/RegionsFromMetadata.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Passes/RegionsFromMetadata.h new file mode 100644 index 0000000000000..3d82a61c90153 --- /dev/null +++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Passes/RegionsFromMetadata.h @@ -0,0 +1,38 @@ +//===- RegionsFromMetadata.h ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// A SandboxIR function pass that builds regions from IR metadata and then runs +// a pipeline of region passes on them. This is useful to test region passes in +// isolation without relying on the output of the bottom-up vectorizer. +// + +#ifndef LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_PASSES_REGIONSFROMMETADATA_H +#define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_PASSES_REGIONSFROMMETADATA_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/SandboxIR/Pass.h" +#include "llvm/SandboxIR/PassManager.h" + +namespace llvm::sandboxir { + +class RegionsFromMetadata final : public FunctionPass { + // The PM containing the pipeline of region passes. + RegionPassManager RPM; + +public: + RegionsFromMetadata(StringRef Pipeline); + bool runOnFunction(Function &F) final; + void printPipeline(raw_ostream &OS) const final { + OS << getName() << "\n"; + RPM.printPipeline(OS); + } +}; + +} // namespace llvm::sandboxir + +#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_PASSES_REGIONSFROMMETADATA_H diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizer.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizer.h index b7cb418c00326..b83744cf9e6cb 100644 --- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizer.h +++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizer.h @@ -11,7 +11,7 @@ #include #include "llvm/IR/PassManager.h" -#include "llvm/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.h" +#include "llvm/SandboxIR/PassManager.h" namespace llvm { @@ -20,8 +20,8 @@ class TargetTransformInfo; class SandboxVectorizerPass : public PassInfoMixin { TargetTransformInfo *TTI = nullptr; - // The main vectorizer pass. - sandboxir::BottomUpVec BottomUpVecPass; + // A pipeline of SandboxIR function passes run by the vectorizer. + sandboxir::FunctionPassManager FPM; bool runImpl(Function &F); diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizerPassBuilder.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizerPassBuilder.h new file mode 100644 index 0000000000000..e3d6ecae836fc --- /dev/null +++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizerPassBuilder.h @@ -0,0 +1,32 @@ +//===- SandboxVectorizerPassBuilder.h ---------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Utility functions so passes with sub-pipelines can create SandboxVectorizer +// passes without replicating the same logic in each pass. +// +#ifndef LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_SANDBOXVECTORIZERPASSBUILDER_H +#define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_SANDBOXVECTORIZERPASSBUILDER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/SandboxIR/Pass.h" + +#include + +namespace llvm::sandboxir { + +class SandboxVectorizerPassBuilder { +public: + static std::unique_ptr createFunctionPass(StringRef Name, + StringRef Args); + static std::unique_ptr createRegionPass(StringRef Name, + StringRef Args); +}; + +} // namespace llvm::sandboxir + +#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_SANDBOXVECTORIZERPASSBUILDER_H diff --git a/llvm/lib/Transforms/Vectorize/CMakeLists.txt b/llvm/lib/Transforms/Vectorize/CMakeLists.txt index 9c2e7c1e0c5bc..f4e98e576379a 100644 --- a/llvm/lib/Transforms/Vectorize/CMakeLists.txt +++ b/llvm/lib/Transforms/Vectorize/CMakeLists.txt @@ -6,7 +6,9 @@ add_llvm_component_library(LLVMVectorize SandboxVectorizer/DependencyGraph.cpp SandboxVectorizer/Interval.cpp SandboxVectorizer/Passes/BottomUpVec.cpp + SandboxVectorizer/Passes/RegionsFromMetadata.cpp SandboxVectorizer/SandboxVectorizer.cpp + SandboxVectorizer/SandboxVectorizerPassBuilder.cpp SandboxVectorizer/SeedCollector.cpp SLPVectorizer.cpp Vectorize.cpp diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.cpp index 77198f932a3ec..6171d5e52b586 100644 --- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.cpp +++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.cpp @@ -7,43 +7,17 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.h" + #include "llvm/ADT/SmallVector.h" #include "llvm/SandboxIR/Function.h" #include "llvm/SandboxIR/Instruction.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Transforms/Vectorize/SandboxVectorizer/Passes/NullPass.h" +#include "llvm/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizerPassBuilder.h" namespace llvm::sandboxir { -static cl::opt - PrintPassPipeline("sbvec-print-pass-pipeline", cl::init(false), cl::Hidden, - cl::desc("Prints the pass pipeline and returns.")); - -/// A magic string for the default pass pipeline. -static const char *DefaultPipelineMagicStr = "*"; - -static cl::opt UserDefinedPassPipeline( - "sbvec-passes", cl::init(DefaultPipelineMagicStr), cl::Hidden, - cl::desc("Comma-separated list of vectorizer passes. If not set " - "we run the predefined pipeline.")); - -static std::unique_ptr createRegionPass(StringRef Name) { -#define REGION_PASS(NAME, CREATE_PASS) \ - if (Name == NAME) \ - return std::make_unique(CREATE_PASS); -#include "PassRegistry.def" - return nullptr; -} - -BottomUpVec::BottomUpVec() : FunctionPass("bottom-up-vec"), RPM("rpm") { - // Create a pipeline to be run on each Region created by BottomUpVec. - if (UserDefinedPassPipeline == DefaultPipelineMagicStr) { - // TODO: Add default passes to RPM. - } else { - // Create the user-defined pipeline. - RPM.setPassPipeline(UserDefinedPassPipeline, createRegionPass); - } -} +BottomUpVec::BottomUpVec(StringRef Pipeline) + : FunctionPass("bottom-up-vec"), + RPM("rpm", Pipeline, SandboxVectorizerPassBuilder::createRegionPass) {} // TODO: This is a temporary function that returns some seeds. // Replace this with SeedCollector's function when it lands. @@ -82,11 +56,6 @@ void BottomUpVec::vectorizeRec(ArrayRef Bndl) { void BottomUpVec::tryVectorize(ArrayRef Bndl) { vectorizeRec(Bndl); } bool BottomUpVec::runOnFunction(Function &F) { - if (PrintPassPipeline) { - RPM.printPipeline(outs()); - return false; - } - Change = false; // TODO: Start from innermost BBs first for (auto &BB : F) { diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/PassRegistry.def b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/PassRegistry.def index bbb0dcba1ea51..0dc72842f1abe 100644 --- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/PassRegistry.def +++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/PassRegistry.def @@ -14,9 +14,19 @@ // NOTE: NO INCLUDE GUARD DESIRED! #ifndef REGION_PASS -#define REGION_PASS(NAME, CREATE_PASS) +#define REGION_PASS(NAME, CLASS_NAME) #endif -REGION_PASS("null", NullPass()) +REGION_PASS("null", ::llvm::sandboxir::NullPass) +REGION_PASS("print-instruction-count", ::llvm::sandboxir::PrintInstructionCount) #undef REGION_PASS + +#ifndef FUNCTION_PASS_WITH_PARAMS +#define FUNCTION_PASS_WITH_PARAMS(NAME, CLASS_NAME) +#endif + +FUNCTION_PASS_WITH_PARAMS("bottom-up-vec", ::llvm::sandboxir::BottomUpVec) +FUNCTION_PASS_WITH_PARAMS("regions-from-metadata", ::llvm::sandboxir::RegionsFromMetadata) + +#undef FUNCTION_PASS_WITH_PARAMS diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/RegionsFromMetadata.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/RegionsFromMetadata.cpp new file mode 100644 index 0000000000000..5887d5e8bc268 --- /dev/null +++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/RegionsFromMetadata.cpp @@ -0,0 +1,29 @@ +//===- RegionsFromMetadata.cpp - A helper to test RegionPasses -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Vectorize/SandboxVectorizer/Passes/RegionsFromMetadata.h" + +#include "llvm/SandboxIR/Region.h" +#include "llvm/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizerPassBuilder.h" + +namespace llvm::sandboxir { + +RegionsFromMetadata::RegionsFromMetadata(StringRef Pipeline) + : FunctionPass("regions-from-metadata"), + RPM("rpm", Pipeline, SandboxVectorizerPassBuilder::createRegionPass) {} + +bool RegionsFromMetadata::runOnFunction(Function &F) { + SmallVector> Regions = + sandboxir::Region::createRegionsFromMD(F); + for (auto &R : Regions) { + RPM.runOnRegion(*R); + } + return false; +} + +} // namespace llvm::sandboxir diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizer.cpp index ba4899cc624e9..c68f9482e337d 100644 --- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizer.cpp +++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizer.cpp @@ -9,14 +9,39 @@ #include "llvm/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizer.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/SandboxIR/Constant.h" -#include "llvm/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizerPassBuilder.h" using namespace llvm; #define SV_NAME "sandbox-vectorizer" #define DEBUG_TYPE SV_NAME -SandboxVectorizerPass::SandboxVectorizerPass() = default; +static cl::opt + PrintPassPipeline("sbvec-print-pass-pipeline", cl::init(false), cl::Hidden, + cl::desc("Prints the pass pipeline and returns.")); + +/// A magic string for the default pass pipeline. +static const char *DefaultPipelineMagicStr = "*"; + +static cl::opt UserDefinedPassPipeline( + "sbvec-passes", cl::init(DefaultPipelineMagicStr), cl::Hidden, + cl::desc("Comma-separated list of vectorizer passes. If not set " + "we run the predefined pipeline.")); + +SandboxVectorizerPass::SandboxVectorizerPass() : FPM("fpm") { + if (UserDefinedPassPipeline == DefaultPipelineMagicStr) { + // TODO: Add region passes to the default pipeline. + FPM.setPassPipeline( + "bottom-up-vec<>", + sandboxir::SandboxVectorizerPassBuilder::createFunctionPass); + } else { + // Create the user-defined pipeline. + FPM.setPassPipeline( + UserDefinedPassPipeline, + sandboxir::SandboxVectorizerPassBuilder::createFunctionPass); + } +} SandboxVectorizerPass::SandboxVectorizerPass(SandboxVectorizerPass &&) = default; @@ -37,6 +62,11 @@ PreservedAnalyses SandboxVectorizerPass::run(Function &F, } bool SandboxVectorizerPass::runImpl(Function &LLVMF) { + if (PrintPassPipeline) { + FPM.printPipeline(outs()); + return false; + } + // If the target claims to have no vector registers early return. if (!TTI->getNumberOfRegisters(TTI->getRegisterClassForType(true))) { LLVM_DEBUG(dbgs() << "SBVec: Target has no vector registers, return.\n"); @@ -52,5 +82,5 @@ bool SandboxVectorizerPass::runImpl(Function &LLVMF) { // Create SandboxIR for LLVMF and run BottomUpVec on it. sandboxir::Context Ctx(LLVMF.getContext()); sandboxir::Function &F = *Ctx.createFunction(&LLVMF); - return BottomUpVecPass.runOnFunction(F); + return FPM.runOnFunction(F); } diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizerPassBuilder.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizerPassBuilder.cpp new file mode 100644 index 0000000000000..5ecf7b2ed0d25 --- /dev/null +++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizerPassBuilder.cpp @@ -0,0 +1,32 @@ +#include "llvm/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizerPassBuilder.h" + +#include "llvm/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.h" +#include "llvm/Transforms/Vectorize/SandboxVectorizer/Passes/NullPass.h" +#include "llvm/Transforms/Vectorize/SandboxVectorizer/Passes/PrintInstructionCount.h" +#include "llvm/Transforms/Vectorize/SandboxVectorizer/Passes/RegionsFromMetadata.h" + +namespace llvm::sandboxir { + +std::unique_ptr +SandboxVectorizerPassBuilder::createRegionPass(StringRef Name, StringRef Args) { +#define REGION_PASS(NAME, CLASS_NAME) \ + if (Name == NAME) { \ + assert(Args.empty() && "Unexpected arguments for pass '" NAME "'."); \ + return std::make_unique(); \ + } +// TODO: Support region passes with params. +#include "Passes/PassRegistry.def" + return nullptr; +} + +std::unique_ptr +SandboxVectorizerPassBuilder::createFunctionPass(StringRef Name, + StringRef Args) { +#define FUNCTION_PASS_WITH_PARAMS(NAME, CLASS_NAME) \ + if (Name == NAME) \ + return std::make_unique(Args); +#include "Passes/PassRegistry.def" + return nullptr; +} + +} // namespace llvm::sandboxir diff --git a/llvm/test/Transforms/SandboxVectorizer/default_pass_pipeline.ll b/llvm/test/Transforms/SandboxVectorizer/default_pass_pipeline.ll index 86bfbee636478..1d7be43336c87 100644 --- a/llvm/test/Transforms/SandboxVectorizer/default_pass_pipeline.ll +++ b/llvm/test/Transforms/SandboxVectorizer/default_pass_pipeline.ll @@ -4,6 +4,7 @@ ; This checks the default pass pipeline for the sandbox vectorizer. define void @pipeline() { +; CHECK: bottom-up-vec ; CHECK: rpm ; CHECK-EMPTY: ret void diff --git a/llvm/test/Transforms/SandboxVectorizer/regions-from-metadata.ll b/llvm/test/Transforms/SandboxVectorizer/regions-from-metadata.ll new file mode 100644 index 0000000000000..3e57bde76e72d --- /dev/null +++ b/llvm/test/Transforms/SandboxVectorizer/regions-from-metadata.ll @@ -0,0 +1,15 @@ +; RUN: opt -disable-output --passes=sandbox-vectorizer \ +; RUN: -sbvec-passes='regions-from-metadata' %s | FileCheck %s + +define i8 @foo(i8 %v0, i8 %v1) { + %t0 = add i8 %v0, 1, !sandboxvec !0 + %t1 = add i8 %t0, %v1, !sandboxvec !1 + %t2 = add i8 %t1, %v1, !sandboxvec !1 + ret i8 %t2 +} + +!0 = distinct !{!"sandboxregion"} +!1 = distinct !{!"sandboxregion"} + +; CHECK: InstructionCount: 1 +; CHECK: InstructionCount: 2 diff --git a/llvm/test/Transforms/SandboxVectorizer/user_pass_pipeline.ll b/llvm/test/Transforms/SandboxVectorizer/user_pass_pipeline.ll index 2e6dab0aa29c7..b11b55ed96019 100644 --- a/llvm/test/Transforms/SandboxVectorizer/user_pass_pipeline.ll +++ b/llvm/test/Transforms/SandboxVectorizer/user_pass_pipeline.ll @@ -1,12 +1,28 @@ -; RUN: opt -passes=sandbox-vectorizer -sbvec-print-pass-pipeline -sbvec-passes=null,null %s -disable-output | FileCheck %s +; RUN: opt -passes=sandbox-vectorizer -sbvec-print-pass-pipeline \ +; RUN: -disable-output -sbvec-passes="bottom-up-vec" %s \ +; RUN: | FileCheck %s +; +; RUN: opt -passes=sandbox-vectorizer -sbvec-print-pass-pipeline \ +; RUN: -disable-output -sbvec-passes="bottom-up-vec<>,regions-from-metadata<>" %s \ +; RUN: | FileCheck --check-prefix CHECK-MULTIPLE-FUNCTION-PASSES %s ; !!!WARNING!!! This won't get updated by update_test_checks.py ! ; This checks the user defined pass pipeline. define void @pipeline() { + ret void +} + +; CHECK: fpm +; CHECK: bottom-up-vec ; CHECK: rpm ; CHECK: null ; CHECK: null ; CHECK-EMPTY: - ret void -} + +; CHECK-MULTIPLE-FUNCTION-PASSES: fpm +; CHECK-MULTIPLE-FUNCTION-PASSES: bottom-up-vec +; CHECK-MULTIPLE-FUNCTION-PASSES: rpm +; CHECK-MULTIPLE-FUNCTION-PASSES: regions-from-metadata +; CHECK-MULTIPLE-FUNCTION-PASSES: rpm +; CHECK-MULTIPLE-FUNCTION-PASSES-EMPTY: diff --git a/llvm/unittests/SandboxIR/PassTest.cpp b/llvm/unittests/SandboxIR/PassTest.cpp index ae7284ecf2deb..866bd8233d803 100644 --- a/llvm/unittests/SandboxIR/PassTest.cpp +++ b/llvm/unittests/SandboxIR/PassTest.cpp @@ -265,39 +265,45 @@ define void @f() { "f"); class FooPass final : public FunctionPass { std::string &Str; + std::string Args; public: - FooPass(std::string &Str) : FunctionPass("foo-pass"), Str(Str) {} + FooPass(std::string &Str, llvm::StringRef Args) + : FunctionPass("foo-pass"), Str(Str), Args(Args.str()) {} bool runOnFunction(Function &F) final { - Str += "foo"; + Str += "foo<" + Args + ">"; return false; } }; class BarPass final : public FunctionPass { std::string &Str; + std::string Args; public: - BarPass(std::string &Str) : FunctionPass("bar-pass"), Str(Str) {} + BarPass(std::string &Str, llvm::StringRef Args) + : FunctionPass("bar-pass"), Str(Str), Args(Args.str()) {} bool runOnFunction(Function &F) final { - Str += "bar"; + Str += "bar<" + Args + ">"; return false; } }; std::string Str; auto CreatePass = - [&Str](llvm::StringRef Name) -> std::unique_ptr { + [&Str](llvm::StringRef Name, + llvm::StringRef Args) -> std::unique_ptr { if (Name == "foo") - return std::make_unique(Str); + return std::make_unique(Str, Args); if (Name == "bar") - return std::make_unique(Str); + return std::make_unique(Str, Args); return nullptr; }; FunctionPassManager FPM("test-fpm"); - FPM.setPassPipeline("foo,bar,foo", CreatePass); + FPM.setPassPipeline("foo,bar>>,foo", + CreatePass); FPM.runOnFunction(*F); - EXPECT_EQ(Str, "foobarfoo"); + EXPECT_EQ(Str, "foobar>>foo<>"); // A second call to setPassPipeline will trigger an assertion in debug mode. #ifndef NDEBUG @@ -308,8 +314,32 @@ define void @f() { // Fresh PM for the death tests so they die from bad pipeline strings, rather // than from multiple setPassPipeline calls. FunctionPassManager FPM2("test-fpm"); + // Bad/empty pass names. EXPECT_DEATH(FPM2.setPassPipeline("bad-pass-name", CreatePass), ".*not registered.*"); - EXPECT_DEATH(FPM2.setPassPipeline("", CreatePass), ".*not registered.*"); - EXPECT_DEATH(FPM2.setPassPipeline(",", CreatePass), ".*not registered.*"); + EXPECT_DEATH(FPM2.setPassPipeline(",", CreatePass), ".*empty pass name.*"); + EXPECT_DEATH(FPM2.setPassPipeline("<>", CreatePass), ".*empty pass name.*"); + EXPECT_DEATH(FPM2.setPassPipeline("<>foo", CreatePass), + ".*empty pass name.*"); + EXPECT_DEATH(FPM2.setPassPipeline("foo,<>", CreatePass), + ".*empty pass name.*"); + + // Mismatched argument brackets. + EXPECT_DEATH(FPM2.setPassPipeline("foo<", CreatePass), ".*Missing '>'.*"); + EXPECT_DEATH(FPM2.setPassPipeline("foo'.*"); + EXPECT_DEATH(FPM2.setPassPipeline("foo", CreatePass), + ".*Missing '>'.*"); + EXPECT_DEATH(FPM2.setPassPipeline("foo>", CreatePass), ".*Unexpected '>'.*"); + EXPECT_DEATH(FPM2.setPassPipeline(">foo", CreatePass), ".*Unexpected '>'.*"); + // Extra garbage between args and next delimiter/end-of-string. + EXPECT_DEATH(FPM2.setPassPipeline("foo>>", CreatePass), + ".*Expected delimiter.*"); + EXPECT_DEATH(FPM2.setPassPipeline("bar<>foo", CreatePass), + ".*Expected delimiter.*"); + EXPECT_DEATH(FPM2.setPassPipeline("bar<>foo,baz", CreatePass), + ".*Expected delimiter.*"); + EXPECT_DEATH(FPM2.setPassPipeline("foo", CreatePass), + ".*Expected delimiter.*"); + EXPECT_DEATH(FPM2.setPassPipeline("foobar", CreatePass), + ".*Expected delimiter.*"); }