Skip to content
Merged
82 changes: 46 additions & 36 deletions llvm/include/llvm/SandboxIR/PassManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#ifndef LLVM_SANDBOXIR_PASSMANAGER_H
#define LLVM_SANDBOXIR_PASSMANAGER_H

#include <memory>

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/SandboxIR/Pass.h"
Expand All @@ -32,25 +34,65 @@ template <typename ParentPass, typename ContainedPass>
class PassManager : public ParentPass {
protected:
/// The list of passes that this pass manager will run.
SmallVector<ContainedPass *> Passes;
SmallVector<std::unique_ptr<ContainedPass>> Passes;

PassManager(StringRef Name) : ParentPass(Name) {}
PassManager(const PassManager &) = delete;
PassManager(PassManager &&) = default;
virtual ~PassManager() = default;
PassManager &operator=(const PassManager &) = delete;

public:
/// Adds \p Pass to the pass pipeline.
void addPass(ContainedPass *Pass) {
void addPass(std::unique_ptr<ContainedPass> Pass) {
// TODO: Check that Pass's class type works with this PassManager type.
Passes.push_back(Pass);
Passes.push_back(std::move(Pass));
}

using CreatePassFunc =
std::function<std::unique_ptr<ContainedPass>(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.
void setPassPipeline(StringRef Pipeline, CreatePassFunc CreatePass) {
static constexpr const char EndToken = '\0';
static constexpr const char PassDelimToken = ',';

assert(Passes.empty() &&
"setPassPipeline called on a non-empty sandboxir::PassManager");
// 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;

// Get the pass that corresponds to PassName and add it to the pass
// manager.
auto Pass = CreatePass(PassName);
if (Pass == nullptr) {
errs() << "Pass '" << PassName << "' not registered!\n";
exit(1);
}
addPass(std::move(Pass));
}
}

#ifndef NDEBUG
void print(raw_ostream &OS) const override {
OS << this->getName();
OS << "(";
// TODO: This should call Pass->print(OS) because Pass may be a PM.
interleave(Passes, OS, [&OS](auto *Pass) { OS << Pass->getName(); }, ",");
interleave(Passes, OS, [&OS](auto &Pass) { OS << Pass->getName(); }, ",");
OS << ")";
}
LLVM_DUMP_METHOD void dump() const override {
Expand Down Expand Up @@ -79,38 +121,6 @@ class RegionPassManager final : public PassManager<RegionPass, RegionPass> {
bool runOnRegion(Region &R) final;
};

/// Owns the passes and provides an API to get a pass by its name.
class PassRegistry {
SmallVector<std::unique_ptr<Pass>, 8> Passes;
DenseMap<StringRef, Pass *> NameToPassMap;

public:
static constexpr const char PassDelimToken = ',';
PassRegistry() = default;
/// Registers \p PassPtr and takes ownership.
Pass &registerPass(std::unique_ptr<Pass> &&PassPtr) {
auto &PassRef = *PassPtr.get();
NameToPassMap[PassRef.getName()] = &PassRef;
Passes.push_back(std::move(PassPtr));
return PassRef;
}
/// \Returns the pass with name \p Name, or null if not registered.
Pass *getPassByName(StringRef Name) const {
auto It = NameToPassMap.find(Name);
return It != NameToPassMap.end() ? It->second : nullptr;
}
/// Creates a pass pipeline and returns the first pass manager.
FunctionPassManager &parseAndCreatePassPipeline(StringRef Pipeline);

#ifndef NDEBUG
void print(raw_ostream &OS) const {
for (const auto &PassPtr : Passes)
OS << PassPtr->getName() << "\n";
}
LLVM_DUMP_METHOD void dump() const;
#endif
};

} // namespace llvm::sandboxir

#endif // LLVM_SANDBOXIR_PASSMANAGER_H
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,24 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/SandboxIR/Constant.h"
#include "llvm/SandboxIR/Pass.h"
#include "llvm/SandboxIR/PassManager.h"
#include "llvm/Transforms/Vectorize/SandboxVectorizer/Legality.h"

namespace llvm::sandboxir {

class RegionPassManager;

class BottomUpVec final : public FunctionPass {
bool Change = false;
LegalityAnalysis Legality;
void vectorizeRec(ArrayRef<Value *> Bndl);
void tryVectorize(ArrayRef<Value *> Seeds);

// The PM containing the pipeline of region passes.
RegionPassManager RPM;

public:
BottomUpVec() : FunctionPass("bottom-up-vec") {}
BottomUpVec();
bool runOnFunction(Function &F) final;
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#ifndef LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_PASSES_NULLPASS_H
#define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_PASSES_NULLPASS_H

#include "llvm/SandboxIR/Pass.h"

namespace llvm::sandboxir {

class Region;

/// A Region pass that does nothing, for use as a placeholder in tests.
class NullPass final : public RegionPass {
public:
NullPass() : RegionPass("null") {}
bool runOnRegion(Region &R) final { return false; }
};

} // namespace llvm::sandboxir

#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_PASSES_NULLPASS_H
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
#ifndef LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_SANDBOXVECTORIZER_H
#define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_SANDBOXVECTORIZER_H

#include <memory>

#include "llvm/IR/PassManager.h"
#include "llvm/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.h"

namespace llvm {

Expand All @@ -17,10 +20,22 @@ class TargetTransformInfo;
class SandboxVectorizerPass : public PassInfoMixin<SandboxVectorizerPass> {
TargetTransformInfo *TTI = nullptr;

public:
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
// The main vectorizer pass.
sandboxir::BottomUpVec BottomUpVecPass;

bool runImpl(Function &F);

public:
// Make sure the constructors/destructors are out-of-line. This works around a
// problem with -DBUILD_SHARED_LIBS=on where components that depend on the
// Vectorizer component can't find the vtable for classes like
// sandboxir::Pass. This way we don't have to make LLVMPasses add a direct
// dependency on SandboxIR.
SandboxVectorizerPass();
SandboxVectorizerPass(SandboxVectorizerPass &&);
~SandboxVectorizerPass();

PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};

} // namespace llvm
Expand Down
44 changes: 4 additions & 40 deletions llvm/lib/SandboxIR/PassManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@

#include "llvm/SandboxIR/PassManager.h"

using namespace llvm::sandboxir;
namespace llvm::sandboxir {

bool FunctionPassManager::runOnFunction(Function &F) {
bool Change = false;
for (FunctionPass *Pass : Passes) {
for (auto &Pass : Passes) {
Change |= Pass->runOnFunction(F);
// TODO: run the verifier.
}
Expand All @@ -22,48 +22,12 @@ bool FunctionPassManager::runOnFunction(Function &F) {

bool RegionPassManager::runOnRegion(Region &R) {
bool Change = false;
for (RegionPass *Pass : Passes) {
for (auto &Pass : Passes) {
Change |= Pass->runOnRegion(R);
// TODO: run the verifier.
}
// TODO: Check ChangeAll against hashes before/after.
return Change;
}

FunctionPassManager &
PassRegistry::parseAndCreatePassPipeline(StringRef Pipeline) {
static constexpr const char EndToken = '\0';
// Add EndToken to the end to ease parsing.
std::string PipelineStr = std::string(Pipeline) + EndToken;
int FlagBeginIdx = 0;
// Start with a FunctionPassManager.
auto &InitialPM = static_cast<FunctionPassManager &>(
registerPass(std::make_unique<FunctionPassManager>("init-fpm")));

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;

// Get the pass that corresponds to PassName and add it to the pass manager.
auto *Pass = getPassByName(PassName);
if (Pass == nullptr) {
errs() << "Pass '" << PassName << "' not registered!\n";
exit(1);
}
// TODO: This is safe for now, but would require proper upcasting once we
// add more Pass sub-classes.
InitialPM.addPass(static_cast<FunctionPass *>(Pass));
}
return InitialPM;
}
#ifndef NDEBUG
void PassRegistry::dump() const {
print(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG
} // namespace llvm::sandboxir
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,41 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/SandboxIR/Function.h"
#include "llvm/SandboxIR/Instruction.h"

using namespace llvm::sandboxir;
#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/Vectorize/SandboxVectorizer/Passes/NullPass.h"

namespace llvm::sandboxir {

static cl::opt<bool>
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<std::string> 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<RegionPass> createRegionPass(StringRef Name) {
#define REGION_PASS(NAME, CREATE_PASS) \
if (Name == NAME) \
return std::make_unique<decltype(CREATE_PASS)>(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);
}
}

// TODO: This is a temporary function that returns some seeds.
// Replace this with SeedCollector's function when it lands.
static llvm::SmallVector<Value *, 4> collectSeeds(BasicBlock &BB) {
Expand All @@ -34,8 +65,6 @@ static SmallVector<Value *, 4> getOperand(ArrayRef<Value *> Bndl,
return Operands;
}

} // namespace llvm::sandboxir

void BottomUpVec::vectorizeRec(ArrayRef<Value *> Bndl) {
auto LegalityRes = Legality.canVectorize(Bndl);
switch (LegalityRes.getSubclassID()) {
Expand All @@ -53,14 +82,23 @@ void BottomUpVec::vectorizeRec(ArrayRef<Value *> Bndl) {
void BottomUpVec::tryVectorize(ArrayRef<Value *> 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) {
// TODO: Replace with proper SeedCollector function.
auto Seeds = collectSeeds(BB);
// TODO: Slice Seeds into smaller chunks.
// TODO: If vectorization succeeds, run the RegionPassManager on the
// resulting region.
if (Seeds.size() >= 2)
tryVectorize(Seeds);
}
return Change;
}

} // namespace llvm::sandboxir
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//===- PassRegistry.def - Registry of passes --------------------*- 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
//
//===----------------------------------------------------------------------===//
//
// This file is used as the registry of sub-passes that are part of the
// SandboxVectorizer pass.
//
//===----------------------------------------------------------------------===//

// NOTE: NO INCLUDE GUARD DESIRED!

#ifndef REGION_PASS
#define REGION_PASS(NAME, CREATE_PASS)
#endif

REGION_PASS("null", NullPass())

#undef REGION_PASS
Loading
Loading