1 //===- PassTest.cpp -------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/SandboxIR/Pass.h"
10 #include "llvm/AsmParser/Parser.h"
11 #include "llvm/IR/Module.h"
12 #include "llvm/SandboxIR/Constant.h"
13 #include "llvm/SandboxIR/Context.h"
14 #include "llvm/SandboxIR/Function.h"
15 #include "llvm/SandboxIR/PassManager.h"
16 #include "llvm/SandboxIR/Region.h"
17 #include "llvm/Support/SourceMgr.h"
18 #include "gtest/gtest.h"
20 using namespace llvm::sandboxir
;
22 struct PassTest
: public testing::Test
{
23 llvm::LLVMContext LLVMCtx
;
24 std::unique_ptr
<llvm::Module
> LLVMM
;
25 std::unique_ptr
<Context
> Ctx
;
27 Function
*parseFunction(const char *IR
, const char *FuncName
) {
28 llvm::SMDiagnostic Err
;
29 LLVMM
= parseAssemblyString(IR
, Err
, LLVMCtx
);
31 Err
.print("PassTest", llvm::errs());
32 Ctx
= std::make_unique
<Context
>(LLVMCtx
);
33 return Ctx
->createFunction(LLVMM
->getFunction(FuncName
));
37 TEST_F(PassTest
, FunctionPass
) {
38 auto *F
= parseFunction(R
"IR(
44 class TestPass final
: public FunctionPass
{
48 TestPass(unsigned &BBCnt
) : FunctionPass("test-pass"), BBCnt(BBCnt
) {}
49 bool runOnFunction(Function
&F
, const Analyses
&A
) final
{
50 for ([[maybe_unused
]] auto &BB
: F
)
56 TestPass
TPass(BBCnt
);
58 EXPECT_EQ(TPass
.getName(), "test-pass");
60 EXPECT_TRUE(llvm::isa
<FunctionPass
>(TPass
));
61 // Check runOnFunction();
62 TPass
.runOnFunction(*F
, Analyses::emptyForTesting());
68 llvm::raw_string_ostream
SS(Buff
);
70 EXPECT_EQ(Buff
, "test-pass");
73 // Check operator<<().
75 llvm::raw_string_ostream
SS(Buff
);
77 EXPECT_EQ(Buff
, "test-pass");
79 // Check pass name assertions.
80 class TestNamePass final
: public FunctionPass
{
82 TestNamePass(llvm::StringRef Name
) : FunctionPass(Name
) {}
83 bool runOnFunction(Function
&F
, const Analyses
&A
) { return false; }
85 EXPECT_DEATH(TestNamePass("white space"), ".*whitespace.*");
86 EXPECT_DEATH(TestNamePass("-dash"), ".*start with.*");
90 TEST_F(PassTest
, RegionPass
) {
91 auto *F
= parseFunction(R
"IR(
92 define i8 @foo(i8 %v0, i8 %v1) {
94 %t1 = add i8 %t0, %v1, !sandboxvec !0
95 %t2 = add i8 %t1, %v1, !sandboxvec !0
99 !0 = distinct !{!"sandboxregion
"}
103 class TestPass final
: public RegionPass
{
107 TestPass(unsigned &InstCount
)
108 : RegionPass("test-pass"), InstCount(InstCount
) {}
109 bool runOnRegion(Region
&R
, const Analyses
&A
) final
{
110 for ([[maybe_unused
]] auto &Inst
: R
) {
116 unsigned InstCount
= 0;
117 TestPass
TPass(InstCount
);
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], Analyses::emptyForTesting());
125 EXPECT_EQ(InstCount
, 2u);
130 llvm::raw_string_ostream
SS(Buff
);
132 EXPECT_EQ(Buff
, "test-pass");
135 // Check operator<<().
137 llvm::raw_string_ostream
SS(Buff
);
139 EXPECT_EQ(Buff
, "test-pass");
141 // Check pass name assertions.
142 class TestNamePass final
: public RegionPass
{
144 TestNamePass(llvm::StringRef Name
) : RegionPass(Name
) {}
145 bool runOnRegion(Region
&F
, const Analyses
&A
) { return false; }
147 EXPECT_DEATH(TestNamePass("white space"), ".*whitespace.*");
148 EXPECT_DEATH(TestNamePass("-dash"), ".*start with.*");
152 TEST_F(PassTest
, FunctionPassManager
) {
153 auto *F
= parseFunction(R
"IR(
159 class TestPass1 final
: public FunctionPass
{
163 TestPass1(unsigned &BBCnt
) : FunctionPass("test-pass1"), BBCnt(BBCnt
) {}
164 bool runOnFunction(Function
&F
, const Analyses
&A
) final
{
165 for ([[maybe_unused
]] auto &BB
: F
)
170 class TestPass2 final
: public FunctionPass
{
174 TestPass2(unsigned &BBCnt
) : FunctionPass("test-pass2"), BBCnt(BBCnt
) {}
175 bool runOnFunction(Function
&F
, const Analyses
&A
) final
{
176 for ([[maybe_unused
]] auto &BB
: F
)
184 FunctionPassManager
FPM("test-fpm");
185 FPM
.addPass(std::make_unique
<TestPass1
>(BBCnt1
));
186 FPM
.addPass(std::make_unique
<TestPass2
>(BBCnt2
));
187 // Check runOnFunction().
188 FPM
.runOnFunction(*F
, Analyses::emptyForTesting());
189 EXPECT_EQ(BBCnt1
, 1u);
190 EXPECT_EQ(BBCnt2
, 1u);
194 llvm::raw_string_ostream
SS(Buff
);
196 EXPECT_EQ(Buff
, "test-fpm(test-pass1,test-pass2)");
200 TEST_F(PassTest
, RegionPassManager
) {
201 auto *F
= parseFunction(R
"IR(
202 define i8 @foo(i8 %v0, i8 %v1) {
204 %t1 = add i8 %t0, %v1, !sandboxvec !0
205 %t2 = add i8 %t1, %v1, !sandboxvec !0
209 !0 = distinct !{!"sandboxregion
"}
213 class TestPass1 final
: public RegionPass
{
217 TestPass1(unsigned &InstCount
)
218 : RegionPass("test-pass1"), InstCount(InstCount
) {}
219 bool runOnRegion(Region
&R
, const Analyses
&A
) final
{
220 for ([[maybe_unused
]] auto &Inst
: R
)
225 class TestPass2 final
: public RegionPass
{
229 TestPass2(unsigned &InstCount
)
230 : RegionPass("test-pass2"), InstCount(InstCount
) {}
231 bool runOnRegion(Region
&R
, const Analyses
&A
) final
{
232 for ([[maybe_unused
]] auto &Inst
: R
)
237 unsigned InstCount1
= 0;
238 unsigned InstCount2
= 0;
240 RegionPassManager
RPM("test-rpm");
241 RPM
.addPass(std::make_unique
<TestPass1
>(InstCount1
));
242 RPM
.addPass(std::make_unique
<TestPass2
>(InstCount2
));
243 // Check runOnRegion().
244 llvm::SmallVector
<std::unique_ptr
<Region
>> Regions
=
245 Region::createRegionsFromMD(*F
);
246 ASSERT_EQ(Regions
.size(), 1u);
247 RPM
.runOnRegion(*Regions
[0], Analyses::emptyForTesting());
248 EXPECT_EQ(InstCount1
, 2u);
249 EXPECT_EQ(InstCount2
, 2u);
253 llvm::raw_string_ostream
SS(Buff
);
255 EXPECT_EQ(Buff
, "test-rpm(test-pass1,test-pass2)");
259 TEST_F(PassTest
, SetPassPipeline
) {
260 auto *F
= parseFunction(R
"IR(
266 class FooPass final
: public FunctionPass
{
271 FooPass(std::string
&Str
, llvm::StringRef Args
)
272 : FunctionPass("foo-pass"), Str(Str
), Args(Args
.str()) {}
273 bool runOnFunction(Function
&F
, const Analyses
&A
) final
{
274 Str
+= "foo<" + Args
+ ">";
278 class BarPass final
: public FunctionPass
{
283 BarPass(std::string
&Str
, llvm::StringRef Args
)
284 : FunctionPass("bar-pass"), Str(Str
), Args(Args
.str()) {}
285 bool runOnFunction(Function
&F
, const Analyses
&A
) final
{
286 Str
+= "bar<" + Args
+ ">";
293 [&Str
](llvm::StringRef Name
,
294 llvm::StringRef Args
) -> std::unique_ptr
<FunctionPass
> {
296 return std::make_unique
<FooPass
>(Str
, Args
);
298 return std::make_unique
<BarPass
>(Str
, Args
);
302 FunctionPassManager
FPM("test-fpm");
303 FPM
.setPassPipeline("foo<abc>,bar<nested1<nested2<nested3>>>,foo",
305 FPM
.runOnFunction(*F
, Analyses::emptyForTesting());
306 EXPECT_EQ(Str
, "foo<abc>bar<nested1<nested2<nested3>>>foo<>");
308 // A second call to setPassPipeline will trigger an assertion in debug mode.
310 EXPECT_DEATH(FPM
.setPassPipeline("bar,bar,foo", CreatePass
),
311 "setPassPipeline called on a non-empty sandboxir::PassManager");
314 // Fresh PM for the death tests so they die from bad pipeline strings, rather
315 // than from multiple setPassPipeline calls.
316 FunctionPassManager
FPM2("test-fpm");
317 // Bad/empty pass names.
318 EXPECT_DEATH(FPM2
.setPassPipeline("bad-pass-name", CreatePass
),
319 ".*not registered.*");
320 EXPECT_DEATH(FPM2
.setPassPipeline(",", CreatePass
), ".*empty pass name.*");
321 EXPECT_DEATH(FPM2
.setPassPipeline("<>", CreatePass
), ".*empty pass name.*");
322 EXPECT_DEATH(FPM2
.setPassPipeline("<>foo", CreatePass
),
323 ".*empty pass name.*");
324 EXPECT_DEATH(FPM2
.setPassPipeline("foo,<>", CreatePass
),
325 ".*empty pass name.*");
327 // Mismatched argument brackets.
328 EXPECT_DEATH(FPM2
.setPassPipeline("foo<", CreatePass
), ".*Missing '>'.*");
329 EXPECT_DEATH(FPM2
.setPassPipeline("foo<bar", CreatePass
), ".*Missing '>'.*");
330 EXPECT_DEATH(FPM2
.setPassPipeline("foo<bar<>", CreatePass
),
332 EXPECT_DEATH(FPM2
.setPassPipeline("foo>", CreatePass
), ".*Unexpected '>'.*");
333 EXPECT_DEATH(FPM2
.setPassPipeline(">foo", CreatePass
), ".*Unexpected '>'.*");
334 // Extra garbage between args and next delimiter/end-of-string.
335 EXPECT_DEATH(FPM2
.setPassPipeline("foo<bar<>>>", CreatePass
),
336 ".*Expected delimiter.*");
337 EXPECT_DEATH(FPM2
.setPassPipeline("bar<>foo", CreatePass
),
338 ".*Expected delimiter.*");
339 EXPECT_DEATH(FPM2
.setPassPipeline("bar<>foo,baz", CreatePass
),
340 ".*Expected delimiter.*");
341 EXPECT_DEATH(FPM2
.setPassPipeline("foo<args><more-args>", CreatePass
),
342 ".*Expected delimiter.*");
343 EXPECT_DEATH(FPM2
.setPassPipeline("foo<args>bar", CreatePass
),
344 ".*Expected delimiter.*");