Skip to content

Commit f35c213

Browse files
authored
[SandboxIR] Add RegionPass/RegionPassManager (#110933)
These classes mirror the existing FunctionPass/FunctionPassManager, and will be used by the sandbox vectorizer to run a pipeline of region passes.
1 parent 6c7a3f8 commit f35c213

File tree

4 files changed

+152
-0
lines changed

4 files changed

+152
-0
lines changed

llvm/include/llvm/SandboxIR/Pass.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
namespace llvm::sandboxir {
1616

1717
class Function;
18+
class Region;
1819

1920
/// The base class of a Sandbox IR Pass.
2021
class Pass {
@@ -24,6 +25,7 @@ class Pass {
2425
const std::string Name;
2526

2627
public:
28+
/// \p Name can't contain any spaces or start with '-'.
2729
Pass(StringRef Name) : Name(Name) {
2830
assert(!Name.contains(' ') &&
2931
"A pass name should not contain whitespaces!");
@@ -47,11 +49,21 @@ class Pass {
4749
/// A pass that runs on a sandbox::Function.
4850
class FunctionPass : public Pass {
4951
public:
52+
/// \p Name can't contain any spaces or start with '-'.
5053
FunctionPass(StringRef Name) : Pass(Name) {}
5154
/// \Returns true if it modifies \p F.
5255
virtual bool runOnFunction(Function &F) = 0;
5356
};
5457

58+
/// A pass that runs on a sandbox::Region.
59+
class RegionPass : public Pass {
60+
public:
61+
/// \p Name can't contain any spaces or start with '-'.
62+
RegionPass(StringRef Name) : Pass(Name) {}
63+
/// \Returns true if it modifies \p R.
64+
virtual bool runOnRegion(Region &R) = 0;
65+
};
66+
5567
} // namespace llvm::sandboxir
5668

5769
#endif // LLVM_SANDBOXIR_PASS_H

llvm/include/llvm/SandboxIR/PassManager.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ class FunctionPassManager final
7373
bool runOnFunction(Function &F) final;
7474
};
7575

76+
class RegionPassManager final : public PassManager<RegionPass, RegionPass> {
77+
public:
78+
RegionPassManager(StringRef Name) : PassManager(Name) {}
79+
bool runOnRegion(Region &R) final;
80+
};
81+
7682
/// Owns the passes and provides an API to get a pass by its name.
7783
class PassRegistry {
7884
SmallVector<std::unique_ptr<Pass>, 8> Passes;

llvm/lib/SandboxIR/PassManager.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@ bool FunctionPassManager::runOnFunction(Function &F) {
2020
return Change;
2121
}
2222

23+
bool RegionPassManager::runOnRegion(Region &R) {
24+
bool Change = false;
25+
for (RegionPass *Pass : Passes) {
26+
Change |= Pass->runOnRegion(R);
27+
// TODO: run the verifier.
28+
}
29+
// TODO: Check ChangeAll against hashes before/after.
30+
return Change;
31+
}
32+
2333
FunctionPassManager &
2434
PassRegistry::parseAndCreatePassPipeline(StringRef Pipeline) {
2535
static constexpr const char EndToken = '\0';

llvm/unittests/SandboxIR/PassTest.cpp

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "llvm/SandboxIR/Context.h"
1414
#include "llvm/SandboxIR/Function.h"
1515
#include "llvm/SandboxIR/PassManager.h"
16+
#include "llvm/SandboxIR/Region.h"
1617
#include "llvm/Support/SourceMgr.h"
1718
#include "gtest/gtest.h"
1819

@@ -86,6 +87,68 @@ define void @foo() {
8687
#endif
8788
}
8889

90+
TEST_F(PassTest, RegionPass) {
91+
auto *F = parseFunction(R"IR(
92+
define i8 @foo(i8 %v0, i8 %v1) {
93+
%t0 = add i8 %v0, 1
94+
%t1 = add i8 %t0, %v1, !sandboxvec !0
95+
%t2 = add i8 %t1, %v1, !sandboxvec !0
96+
ret i8 %t1
97+
}
98+
99+
!0 = distinct !{!"sandboxregion"}
100+
)IR",
101+
"foo");
102+
103+
class TestPass final : public RegionPass {
104+
unsigned &InstCount;
105+
106+
public:
107+
TestPass(unsigned &InstCount)
108+
: RegionPass("test-pass"), InstCount(InstCount) {}
109+
bool runOnRegion(Region &R) final {
110+
for ([[maybe_unused]] auto &Inst : R) {
111+
++InstCount;
112+
}
113+
return false;
114+
}
115+
};
116+
unsigned InstCount = 0;
117+
TestPass TPass(InstCount);
118+
// Check getName(),
119+
EXPECT_EQ(TPass.getName(), "test-pass");
120+
// Check runOnRegion();
121+
llvm::SmallVector<std::unique_ptr<Region>> Regions =
122+
Region::createRegionsFromMD(*F);
123+
ASSERT_EQ(Regions.size(), 1u);
124+
TPass.runOnRegion(*Regions[0]);
125+
EXPECT_EQ(InstCount, 2u);
126+
#ifndef NDEBUG
127+
{
128+
// Check print().
129+
std::string Buff;
130+
llvm::raw_string_ostream SS(Buff);
131+
TPass.print(SS);
132+
EXPECT_EQ(Buff, "test-pass");
133+
}
134+
{
135+
// Check operator<<().
136+
std::string Buff;
137+
llvm::raw_string_ostream SS(Buff);
138+
SS << TPass;
139+
EXPECT_EQ(Buff, "test-pass");
140+
}
141+
// Check pass name assertions.
142+
class TestNamePass final : public RegionPass {
143+
public:
144+
TestNamePass(llvm::StringRef Name) : RegionPass(Name) {}
145+
bool runOnRegion(Region &F) { return false; }
146+
};
147+
EXPECT_DEATH(TestNamePass("white space"), ".*whitespace.*");
148+
EXPECT_DEATH(TestNamePass("-dash"), ".*start with.*");
149+
#endif
150+
}
151+
89152
TEST_F(PassTest, FunctionPassManager) {
90153
auto *F = parseFunction(R"IR(
91154
define void @foo() {
@@ -136,6 +199,67 @@ define void @foo() {
136199
#endif // NDEBUG
137200
}
138201

202+
TEST_F(PassTest, RegionPassManager) {
203+
auto *F = parseFunction(R"IR(
204+
define i8 @foo(i8 %v0, i8 %v1) {
205+
%t0 = add i8 %v0, 1
206+
%t1 = add i8 %t0, %v1, !sandboxvec !0
207+
%t2 = add i8 %t1, %v1, !sandboxvec !0
208+
ret i8 %t1
209+
}
210+
211+
!0 = distinct !{!"sandboxregion"}
212+
)IR",
213+
"foo");
214+
215+
class TestPass1 final : public RegionPass {
216+
unsigned &InstCount;
217+
218+
public:
219+
TestPass1(unsigned &InstCount)
220+
: RegionPass("test-pass1"), InstCount(InstCount) {}
221+
bool runOnRegion(Region &R) final {
222+
for ([[maybe_unused]] auto &Inst : R)
223+
++InstCount;
224+
return false;
225+
}
226+
};
227+
class TestPass2 final : public RegionPass {
228+
unsigned &InstCount;
229+
230+
public:
231+
TestPass2(unsigned &InstCount)
232+
: RegionPass("test-pass2"), InstCount(InstCount) {}
233+
bool runOnRegion(Region &R) final {
234+
for ([[maybe_unused]] auto &Inst : R)
235+
++InstCount;
236+
return false;
237+
}
238+
};
239+
unsigned InstCount1 = 0;
240+
unsigned InstCount2 = 0;
241+
TestPass1 TPass1(InstCount1);
242+
TestPass2 TPass2(InstCount2);
243+
244+
RegionPassManager RPM("test-rpm");
245+
RPM.addPass(&TPass1);
246+
RPM.addPass(&TPass2);
247+
// Check runOnRegion().
248+
llvm::SmallVector<std::unique_ptr<Region>> Regions =
249+
Region::createRegionsFromMD(*F);
250+
ASSERT_EQ(Regions.size(), 1u);
251+
RPM.runOnRegion(*Regions[0]);
252+
EXPECT_EQ(InstCount1, 2u);
253+
EXPECT_EQ(InstCount2, 2u);
254+
#ifndef NDEBUG
255+
// Check dump().
256+
std::string Buff;
257+
llvm::raw_string_ostream SS(Buff);
258+
RPM.print(SS);
259+
EXPECT_EQ(Buff, "test-rpm(test-pass1,test-pass2)");
260+
#endif // NDEBUG
261+
}
262+
139263
TEST_F(PassTest, PassRegistry) {
140264
class TestPass1 final : public FunctionPass {
141265
public:

0 commit comments

Comments
 (0)