[AArch64] Fix SDNode type mismatches between *.td files and ISel (#116523)
[llvm-project.git] / llvm / unittests / SandboxIR / PassTest.cpp
blob751aedefd8fe2d5f736539d360f52c86ca4eb5cf
1 //===- PassTest.cpp -------------------------------------------------------===//
2 //
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
6 //
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);
30 if (!LLVMM)
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(
39 define void @foo() {
40 ret void
42 )IR",
43 "foo");
44 class TestPass final : public FunctionPass {
45 unsigned &BBCnt;
47 public:
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)
51 ++BBCnt;
52 return false;
55 unsigned BBCnt = 0;
56 TestPass TPass(BBCnt);
57 // Check getName(),
58 EXPECT_EQ(TPass.getName(), "test-pass");
59 // Check classof().
60 EXPECT_TRUE(llvm::isa<FunctionPass>(TPass));
61 // Check runOnFunction();
62 TPass.runOnFunction(*F, Analyses::emptyForTesting());
63 EXPECT_EQ(BBCnt, 1u);
64 #ifndef NDEBUG
66 // Check print().
67 std::string Buff;
68 llvm::raw_string_ostream SS(Buff);
69 TPass.print(SS);
70 EXPECT_EQ(Buff, "test-pass");
73 // Check operator<<().
74 std::string Buff;
75 llvm::raw_string_ostream SS(Buff);
76 SS << TPass;
77 EXPECT_EQ(Buff, "test-pass");
79 // Check pass name assertions.
80 class TestNamePass final : public FunctionPass {
81 public:
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.*");
87 #endif
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
99 !0 = distinct !{!"sandboxregion"}
100 )IR",
101 "foo");
103 class TestPass final : public RegionPass {
104 unsigned &InstCount;
106 public:
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) {
111 ++InstCount;
113 return false;
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], Analyses::emptyForTesting());
125 EXPECT_EQ(InstCount, 2u);
126 #ifndef NDEBUG
128 // Check print().
129 std::string Buff;
130 llvm::raw_string_ostream SS(Buff);
131 TPass.print(SS);
132 EXPECT_EQ(Buff, "test-pass");
135 // Check operator<<().
136 std::string Buff;
137 llvm::raw_string_ostream SS(Buff);
138 SS << TPass;
139 EXPECT_EQ(Buff, "test-pass");
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, const Analyses &A) { return false; }
147 EXPECT_DEATH(TestNamePass("white space"), ".*whitespace.*");
148 EXPECT_DEATH(TestNamePass("-dash"), ".*start with.*");
149 #endif
152 TEST_F(PassTest, FunctionPassManager) {
153 auto *F = parseFunction(R"IR(
154 define void @foo() {
155 ret void
157 )IR",
158 "foo");
159 class TestPass1 final : public FunctionPass {
160 unsigned &BBCnt;
162 public:
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)
166 ++BBCnt;
167 return false;
170 class TestPass2 final : public FunctionPass {
171 unsigned &BBCnt;
173 public:
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)
177 ++BBCnt;
178 return false;
181 unsigned BBCnt1 = 0;
182 unsigned BBCnt2 = 0;
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);
191 #ifndef NDEBUG
192 // Check dump().
193 std::string Buff;
194 llvm::raw_string_ostream SS(Buff);
195 FPM.print(SS);
196 EXPECT_EQ(Buff, "test-fpm(test-pass1,test-pass2)");
197 #endif // NDEBUG
200 TEST_F(PassTest, RegionPassManager) {
201 auto *F = parseFunction(R"IR(
202 define i8 @foo(i8 %v0, i8 %v1) {
203 %t0 = add i8 %v0, 1
204 %t1 = add i8 %t0, %v1, !sandboxvec !0
205 %t2 = add i8 %t1, %v1, !sandboxvec !0
206 ret i8 %t1
209 !0 = distinct !{!"sandboxregion"}
210 )IR",
211 "foo");
213 class TestPass1 final : public RegionPass {
214 unsigned &InstCount;
216 public:
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)
221 ++InstCount;
222 return false;
225 class TestPass2 final : public RegionPass {
226 unsigned &InstCount;
228 public:
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)
233 ++InstCount;
234 return false;
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);
250 #ifndef NDEBUG
251 // Check dump().
252 std::string Buff;
253 llvm::raw_string_ostream SS(Buff);
254 RPM.print(SS);
255 EXPECT_EQ(Buff, "test-rpm(test-pass1,test-pass2)");
256 #endif // NDEBUG
259 TEST_F(PassTest, SetPassPipeline) {
260 auto *F = parseFunction(R"IR(
261 define void @f() {
262 ret void
264 )IR",
265 "f");
266 class FooPass final : public FunctionPass {
267 std::string &Str;
268 std::string Args;
270 public:
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 + ">";
275 return false;
278 class BarPass final : public FunctionPass {
279 std::string &Str;
280 std::string Args;
282 public:
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 + ">";
287 return false;
291 std::string Str;
292 auto CreatePass =
293 [&Str](llvm::StringRef Name,
294 llvm::StringRef Args) -> std::unique_ptr<FunctionPass> {
295 if (Name == "foo")
296 return std::make_unique<FooPass>(Str, Args);
297 if (Name == "bar")
298 return std::make_unique<BarPass>(Str, Args);
299 return nullptr;
302 FunctionPassManager FPM("test-fpm");
303 FPM.setPassPipeline("foo<abc>,bar<nested1<nested2<nested3>>>,foo",
304 CreatePass);
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.
309 #ifndef NDEBUG
310 EXPECT_DEATH(FPM.setPassPipeline("bar,bar,foo", CreatePass),
311 "setPassPipeline called on a non-empty sandboxir::PassManager");
312 #endif
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),
331 ".*Missing '>'.*");
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.*");