Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions llvm/include/llvm/SandboxIR/PassManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,44 @@ class PassManager : public ParentPass {
// TODO: Check that Pass's class type works with this PassManager type.
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 = ',';

Passes.clear();
// 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,41 +35,13 @@ static std::unique_ptr<RegionPass> createRegionPass(StringRef Name) {
return nullptr;
}

/// Adds to `RPM` a sequence of region passes described by `Pipeline`.
static void parseAndCreatePassPipeline(RegionPassManager &RPM,
StringRef Pipeline) {
static constexpr const char EndToken = '\0';
static constexpr const char PassDelimToken = ',';
// 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 RegionPass = createRegionPass(PassName);
if (RegionPass == nullptr) {
errs() << "Pass '" << PassName << "' not registered!\n";
exit(1);
}
RPM.addPass(std::move(RegionPass));
}
}

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.
parseAndCreatePassPipeline(RPM, UserDefinedPassPipeline);
RPM.setPassPipeline(UserDefinedPassPipeline, createRegionPass);
}
}

Expand Down
55 changes: 55 additions & 0 deletions llvm/unittests/SandboxIR/PassTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,3 +255,58 @@ define i8 @foo(i8 %v0, i8 %v1) {
EXPECT_EQ(Buff, "test-rpm(test-pass1,test-pass2)");
#endif // NDEBUG
}

TEST_F(PassTest, SetPassPipeline) {
auto *F = parseFunction(R"IR(
define void @f() {
ret void
}
)IR",
"f");
class FooPass final : public FunctionPass {
std::string &Str;

public:
FooPass(std::string &Str) : FunctionPass("foo-pass"), Str(Str) {}
bool runOnFunction(Function &F) final {
Str += "foo";
return false;
}
};
class BarPass final : public FunctionPass {
std::string &Str;

public:
BarPass(std::string &Str) : FunctionPass("bar-pass"), Str(Str) {}
bool runOnFunction(Function &F) final {
Str += "bar";
return false;
}
};

std::string Str;
auto CreatePass =
[&Str](llvm::StringRef Name) -> std::unique_ptr<FunctionPass> {
if (Name == "foo")
return std::make_unique<FooPass>(Str);
if (Name == "bar")
return std::make_unique<BarPass>(Str);
return nullptr;
};

FunctionPassManager FPM("test-fpm");
FPM.setPassPipeline("foo,bar,foo", CreatePass);
FPM.runOnFunction(*F);
EXPECT_EQ(Str, "foobarfoo");

// Check that a second call to setPassPipeline clears the previous pipeline.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we allow a second call to setPassPipeline() ? Shouldn't we crash if we try to do so instead?

Str.clear();
FPM.setPassPipeline("bar,bar,foo", CreatePass);
FPM.runOnFunction(*F);
EXPECT_EQ(Str, "barbarfoo");

EXPECT_DEATH(FPM.setPassPipeline("bad-pass-name", CreatePass),
".*not registered.*");
EXPECT_DEATH(FPM.setPassPipeline("", CreatePass), ".*not registered.*");
EXPECT_DEATH(FPM.setPassPipeline(",", CreatePass), ".*not registered.*");
}
Loading