1//===- llvm/unittest/IR/PassManager.cpp - PassManager tests ---------------===//
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//===----------------------------------------------------------------------===//
8
9#include "llvm/IR/PassManager.h"
10#include "llvm/Analysis/AssumptionCache.h"
11#include "llvm/Analysis/TargetTransformInfo.h"
12#include "llvm/AsmParser/Parser.h"
13#include "llvm/IR/Dominators.h"
14#include "llvm/IR/Function.h"
15#include "llvm/IR/LLVMContext.h"
16#include "llvm/IR/Module.h"
17#include "llvm/IR/PassManagerImpl.h"
18#include "llvm/Passes/StandardInstrumentations.h"
19#include "llvm/Support/SourceMgr.h"
20#include "llvm/Transforms/Scalar/SimplifyCFG.h"
21#include "gtest/gtest.h"
22
23using namespace llvm;
24
25namespace {
26
27class TestFunctionAnalysis : public AnalysisInfoMixin<TestFunctionAnalysis> {
28public:
29 struct Result {
30 Result(int Count) : InstructionCount(Count) {}
31 int InstructionCount;
32 bool invalidate(Function &, const PreservedAnalyses &PA,
33 FunctionAnalysisManager::Invalidator &) {
34 // Check whether the analysis or all analyses on functions have been
35 // preserved.
36 auto PAC = PA.getChecker<TestFunctionAnalysis>();
37 return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>());
38 }
39 };
40
41 TestFunctionAnalysis(int &Runs) : Runs(Runs) {}
42
43 /// Run the analysis pass over the function and return a result.
44 Result run(Function &F, FunctionAnalysisManager &AM) {
45 ++Runs;
46 int Count = 0;
47 for (Function::iterator BBI = F.begin(), BBE = F.end(); BBI != BBE; ++BBI)
48 for (BasicBlock::iterator II = BBI->begin(), IE = BBI->end(); II != IE;
49 ++II)
50 ++Count;
51 return Result(Count);
52 }
53
54private:
55 friend AnalysisInfoMixin<TestFunctionAnalysis>;
56 static AnalysisKey Key;
57
58 int &Runs;
59};
60
61AnalysisKey TestFunctionAnalysis::Key;
62
63class TestModuleAnalysis : public AnalysisInfoMixin<TestModuleAnalysis> {
64public:
65 struct Result {
66 Result(int Count) : FunctionCount(Count) {}
67 int FunctionCount;
68 bool invalidate(Module &, const PreservedAnalyses &PA,
69 ModuleAnalysisManager::Invalidator &) {
70 // Check whether the analysis or all analyses on modules have been
71 // preserved.
72 auto PAC = PA.getChecker<TestModuleAnalysis>();
73 return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Module>>());
74 }
75 };
76
77 TestModuleAnalysis(int &Runs) : Runs(Runs) {}
78
79 Result run(Module &M, ModuleAnalysisManager &AM) {
80 ++Runs;
81 int Count = 0;
82 for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
83 ++Count;
84 return Result(Count);
85 }
86
87private:
88 friend AnalysisInfoMixin<TestModuleAnalysis>;
89 static AnalysisKey Key;
90
91 int &Runs;
92};
93
94AnalysisKey TestModuleAnalysis::Key;
95
96struct TestModulePass : PassInfoMixin<TestModulePass> {
97 TestModulePass(int &RunCount) : RunCount(RunCount) {}
98
99 PreservedAnalyses run(Module &M, ModuleAnalysisManager &) {
100 ++RunCount;
101 return PreservedAnalyses::none();
102 }
103
104 int &RunCount;
105};
106
107struct TestPreservingModulePass : PassInfoMixin<TestPreservingModulePass> {
108 PreservedAnalyses run(Module &M, ModuleAnalysisManager &) {
109 return PreservedAnalyses::all();
110 }
111};
112
113struct TestFunctionPass : PassInfoMixin<TestFunctionPass> {
114 TestFunctionPass(int &RunCount, int &AnalyzedInstrCount,
115 int &AnalyzedFunctionCount, ModuleAnalysisManager &MAM,
116 bool OnlyUseCachedResults = false)
117 : RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount),
118 AnalyzedFunctionCount(AnalyzedFunctionCount), MAM(MAM),
119 OnlyUseCachedResults(OnlyUseCachedResults) {}
120
121 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
122 ++RunCount;
123
124 // Getting a cached result that isn't stateless through the proxy will
125 // trigger an assert:
126 // auto &ModuleProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
127 // Use MAM, for the purposes of this unittest.
128 if (TestModuleAnalysis::Result *TMA =
129 MAM.getCachedResult<TestModuleAnalysis>(IR&: *F.getParent())) {
130 AnalyzedFunctionCount += TMA->FunctionCount;
131 }
132
133 if (OnlyUseCachedResults) {
134 // Hack to force the use of the cached interface.
135 if (TestFunctionAnalysis::Result *AR =
136 AM.getCachedResult<TestFunctionAnalysis>(IR&: F))
137 AnalyzedInstrCount += AR->InstructionCount;
138 } else {
139 // Typical path just runs the analysis as needed.
140 TestFunctionAnalysis::Result &AR = AM.getResult<TestFunctionAnalysis>(IR&: F);
141 AnalyzedInstrCount += AR.InstructionCount;
142 }
143
144 return PreservedAnalyses::all();
145 }
146
147 int &RunCount;
148 int &AnalyzedInstrCount;
149 int &AnalyzedFunctionCount;
150 ModuleAnalysisManager &MAM;
151 bool OnlyUseCachedResults;
152};
153
154// A test function pass that invalidates all function analyses for a function
155// with a specific name.
156struct TestInvalidationFunctionPass
157 : PassInfoMixin<TestInvalidationFunctionPass> {
158 TestInvalidationFunctionPass(StringRef FunctionName) : Name(FunctionName) {}
159
160 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
161 return F.getName() == Name ? PreservedAnalyses::none()
162 : PreservedAnalyses::all();
163 }
164
165 StringRef Name;
166};
167
168std::unique_ptr<Module> parseIR(LLVMContext &Context, const char *IR) {
169 SMDiagnostic Err;
170 return parseAssemblyString(AsmString: IR, Err, Context);
171}
172
173class PassManagerTest : public ::testing::Test {
174protected:
175 LLVMContext Context;
176 std::unique_ptr<Module> M;
177
178public:
179 PassManagerTest()
180 : M(parseIR(Context, IR: "define void @f() {\n"
181 "entry:\n"
182 " call void @g()\n"
183 " call void @h()\n"
184 " ret void\n"
185 "}\n"
186 "define void @g() {\n"
187 " ret void\n"
188 "}\n"
189 "define void @h() {\n"
190 " ret void\n"
191 "}\n")) {}
192};
193
194TEST(PreservedAnalysesTest, Basic) {
195 PreservedAnalyses PA1 = PreservedAnalyses();
196 {
197 auto PAC = PA1.getChecker<TestFunctionAnalysis>();
198 EXPECT_FALSE(PAC.preserved());
199 EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());
200 }
201 {
202 auto PAC = PA1.getChecker<TestModuleAnalysis>();
203 EXPECT_FALSE(PAC.preserved());
204 EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Module>>());
205 }
206 auto PA2 = PreservedAnalyses::none();
207 {
208 auto PAC = PA2.getChecker<TestFunctionAnalysis>();
209 EXPECT_FALSE(PAC.preserved());
210 EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());
211 }
212 auto PA3 = PreservedAnalyses::all();
213 {
214 auto PAC = PA3.getChecker<TestFunctionAnalysis>();
215 EXPECT_TRUE(PAC.preserved());
216 EXPECT_TRUE(PAC.preservedSet<AllAnalysesOn<Function>>());
217 }
218 PreservedAnalyses PA4 = PA1;
219 {
220 auto PAC = PA4.getChecker<TestFunctionAnalysis>();
221 EXPECT_FALSE(PAC.preserved());
222 EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());
223 }
224 PA4 = PA3;
225 {
226 auto PAC = PA4.getChecker<TestFunctionAnalysis>();
227 EXPECT_TRUE(PAC.preserved());
228 EXPECT_TRUE(PAC.preservedSet<AllAnalysesOn<Function>>());
229 }
230 PA4 = std::move(PA2);
231 {
232 auto PAC = PA4.getChecker<TestFunctionAnalysis>();
233 EXPECT_FALSE(PAC.preserved());
234 EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());
235 }
236 auto PA5 = PreservedAnalyses::allInSet<AllAnalysesOn<Function>>();
237 {
238 auto PAC = PA5.getChecker<TestFunctionAnalysis>();
239 EXPECT_FALSE(PAC.preserved());
240 EXPECT_TRUE(PAC.preservedSet<AllAnalysesOn<Function>>());
241 EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Module>>());
242 }
243}
244
245TEST(PreservedAnalysesTest, Preserve) {
246 auto PA = PreservedAnalyses::none();
247 PA.preserve<TestFunctionAnalysis>();
248 EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>().preserved());
249 EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>().preserved());
250 PA.preserve<TestModuleAnalysis>();
251 EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>().preserved());
252 EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>().preserved());
253
254 // Redundant calls are fine.
255 PA.preserve<TestFunctionAnalysis>();
256 EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>().preserved());
257 EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>().preserved());
258}
259
260TEST(PreservedAnalysesTest, PreserveSets) {
261 auto PA = PreservedAnalyses::none();
262 PA.preserveSet<AllAnalysesOn<Function>>();
263 EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()
264 .preservedSet<AllAnalysesOn<Function>>());
265 EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>()
266 .preservedSet<AllAnalysesOn<Module>>());
267 PA.preserveSet<AllAnalysesOn<Module>>();
268 EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()
269 .preservedSet<AllAnalysesOn<Function>>());
270 EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>()
271 .preservedSet<AllAnalysesOn<Module>>());
272
273 // Mixing is fine.
274 PA.preserve<TestFunctionAnalysis>();
275 EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()
276 .preservedSet<AllAnalysesOn<Function>>());
277 EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>()
278 .preservedSet<AllAnalysesOn<Module>>());
279
280 // Redundant calls are fine.
281 PA.preserveSet<AllAnalysesOn<Module>>();
282 EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()
283 .preservedSet<AllAnalysesOn<Function>>());
284 EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>()
285 .preservedSet<AllAnalysesOn<Module>>());
286}
287
288TEST(PreservedAnalysisTest, Intersect) {
289 // Setup the initial sets.
290 auto PA1 = PreservedAnalyses::none();
291 PA1.preserve<TestFunctionAnalysis>();
292 PA1.preserveSet<AllAnalysesOn<Module>>();
293 auto PA2 = PreservedAnalyses::none();
294 PA2.preserve<TestFunctionAnalysis>();
295 PA2.preserveSet<AllAnalysesOn<Function>>();
296 PA2.preserve<TestModuleAnalysis>();
297 PA2.preserveSet<AllAnalysesOn<Module>>();
298 auto PA3 = PreservedAnalyses::none();
299 PA3.preserve<TestModuleAnalysis>();
300 PA3.preserveSet<AllAnalysesOn<Function>>();
301
302 // Self intersection is a no-op.
303 auto Intersected = PA1;
304 Intersected.intersect(Arg: PA1);
305 EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
306 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
307 .preservedSet<AllAnalysesOn<Function>>());
308 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
309 EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
310 .preservedSet<AllAnalysesOn<Module>>());
311
312 // Intersecting with all is a no-op.
313 Intersected.intersect(Arg: PreservedAnalyses::all());
314 EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
315 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
316 .preservedSet<AllAnalysesOn<Function>>());
317 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
318 EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
319 .preservedSet<AllAnalysesOn<Module>>());
320
321 // Intersecting a narrow set with a more broad set is the narrow set.
322 Intersected.intersect(Arg: PA2);
323 EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
324 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
325 .preservedSet<AllAnalysesOn<Function>>());
326 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
327 EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
328 .preservedSet<AllAnalysesOn<Module>>());
329
330 // Intersecting a broad set with a more narrow set is the narrow set.
331 Intersected = PA2;
332 Intersected.intersect(Arg: PA1);
333 EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
334 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
335 .preservedSet<AllAnalysesOn<Function>>());
336 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
337 EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
338 .preservedSet<AllAnalysesOn<Module>>());
339
340 // Intersecting with empty clears.
341 Intersected.intersect(Arg: PreservedAnalyses::none());
342 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
343 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
344 .preservedSet<AllAnalysesOn<Function>>());
345 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
346 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>()
347 .preservedSet<AllAnalysesOn<Module>>());
348
349 // Intersecting non-overlapping clears.
350 Intersected = PA1;
351 Intersected.intersect(Arg: PA3);
352 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
353 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
354 .preservedSet<AllAnalysesOn<Function>>());
355 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
356 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>()
357 .preservedSet<AllAnalysesOn<Module>>());
358
359 // Intersecting with moves works in when there is storage on both sides.
360 Intersected = PA1;
361 auto Tmp = PA2;
362 Intersected.intersect(Arg: std::move(Tmp));
363 EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
364 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
365 .preservedSet<AllAnalysesOn<Function>>());
366 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
367 EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
368 .preservedSet<AllAnalysesOn<Module>>());
369
370 // Intersecting with move works for incoming all and existing all.
371 auto Tmp2 = PreservedAnalyses::all();
372 Intersected.intersect(Arg: std::move(Tmp2));
373 EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
374 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
375 .preservedSet<AllAnalysesOn<Function>>());
376 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
377 EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
378 .preservedSet<AllAnalysesOn<Module>>());
379 Intersected = PreservedAnalyses::all();
380 auto Tmp3 = PA1;
381 Intersected.intersect(Arg: std::move(Tmp3));
382 EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
383 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
384 .preservedSet<AllAnalysesOn<Function>>());
385 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
386 EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
387 .preservedSet<AllAnalysesOn<Module>>());
388}
389
390TEST(PreservedAnalysisTest, Abandon) {
391 auto PA = PreservedAnalyses::none();
392
393 // We can abandon things after they are preserved.
394 PA.preserve<TestFunctionAnalysis>();
395 PA.abandon<TestFunctionAnalysis>();
396 EXPECT_FALSE(PA.getChecker<TestFunctionAnalysis>().preserved());
397
398 // Repeated is fine, and abandoning if they were never preserved is fine.
399 PA.abandon<TestFunctionAnalysis>();
400 EXPECT_FALSE(PA.getChecker<TestFunctionAnalysis>().preserved());
401 PA.abandon<TestModuleAnalysis>();
402 EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>().preserved());
403
404 // Even if the sets are preserved, the abandoned analyses' checker won't
405 // return true for those sets.
406 PA.preserveSet<AllAnalysesOn<Function>>();
407 PA.preserveSet<AllAnalysesOn<Module>>();
408 EXPECT_FALSE(PA.getChecker<TestFunctionAnalysis>()
409 .preservedSet<AllAnalysesOn<Function>>());
410 EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>()
411 .preservedSet<AllAnalysesOn<Module>>());
412
413 // But an arbitrary (opaque) analysis will still observe the sets as
414 // preserved. This also checks that we can use an explicit ID rather than
415 // a type.
416 AnalysisKey FakeKey, *FakeID = &FakeKey;
417 EXPECT_TRUE(PA.getChecker(FakeID).preservedSet<AllAnalysesOn<Function>>());
418 EXPECT_TRUE(PA.getChecker(FakeID).preservedSet<AllAnalysesOn<Module>>());
419}
420
421TEST_F(PassManagerTest, Basic) {
422 FunctionAnalysisManager FAM;
423 int FunctionAnalysisRuns = 0;
424 FAM.registerPass(PassBuilder: [&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
425
426 ModuleAnalysisManager MAM;
427 int ModuleAnalysisRuns = 0;
428 MAM.registerPass(PassBuilder: [&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
429 MAM.registerPass(PassBuilder: [&] { return FunctionAnalysisManagerModuleProxy(FAM); });
430 FAM.registerPass(PassBuilder: [&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
431
432 MAM.registerPass(PassBuilder: [&] { return PassInstrumentationAnalysis(); });
433 FAM.registerPass(PassBuilder: [&] { return PassInstrumentationAnalysis(); });
434
435 ModulePassManager MPM;
436
437 // Count the runs over a Function.
438 int FunctionPassRunCount1 = 0;
439 int AnalyzedInstrCount1 = 0;
440 int AnalyzedFunctionCount1 = 0;
441 {
442 // Pointless scoped copy to test move assignment.
443 ModulePassManager NestedMPM;
444 FunctionPassManager FPM;
445 {
446 // Pointless scope to test move assignment.
447 FunctionPassManager NestedFPM;
448 NestedFPM.addPass(Pass: TestFunctionPass(FunctionPassRunCount1,
449 AnalyzedInstrCount1,
450 AnalyzedFunctionCount1, MAM));
451 FPM = std::move(NestedFPM);
452 }
453 NestedMPM.addPass(Pass: createModuleToFunctionPassAdaptor(Pass: std::move(FPM)));
454 MPM = std::move(NestedMPM);
455 }
456
457 // Count the runs over a module.
458 int ModulePassRunCount = 0;
459 MPM.addPass(Pass: TestModulePass(ModulePassRunCount));
460
461 // Count the runs over a Function in a separate manager.
462 int FunctionPassRunCount2 = 0;
463 int AnalyzedInstrCount2 = 0;
464 int AnalyzedFunctionCount2 = 0;
465 {
466 FunctionPassManager FPM;
467 FPM.addPass(Pass: TestFunctionPass(FunctionPassRunCount2, AnalyzedInstrCount2,
468 AnalyzedFunctionCount2, MAM));
469 MPM.addPass(Pass: createModuleToFunctionPassAdaptor(Pass: std::move(FPM)));
470 }
471
472 // A third function pass manager but with only preserving intervening passes
473 // and with a function pass that invalidates exactly one analysis.
474 MPM.addPass(Pass: TestPreservingModulePass());
475 int FunctionPassRunCount3 = 0;
476 int AnalyzedInstrCount3 = 0;
477 int AnalyzedFunctionCount3 = 0;
478 {
479 FunctionPassManager FPM;
480 FPM.addPass(Pass: TestFunctionPass(FunctionPassRunCount3, AnalyzedInstrCount3,
481 AnalyzedFunctionCount3, MAM));
482 FPM.addPass(Pass: TestInvalidationFunctionPass("f"));
483 MPM.addPass(Pass: createModuleToFunctionPassAdaptor(Pass: std::move(FPM)));
484 }
485
486 // A fourth function pass manager but with only preserving intervening
487 // passes but triggering the module analysis.
488 MPM.addPass(Pass: RequireAnalysisPass<TestModuleAnalysis, Module>());
489 int FunctionPassRunCount4 = 0;
490 int AnalyzedInstrCount4 = 0;
491 int AnalyzedFunctionCount4 = 0;
492 {
493 FunctionPassManager FPM;
494 FPM.addPass(Pass: TestFunctionPass(FunctionPassRunCount4, AnalyzedInstrCount4,
495 AnalyzedFunctionCount4, MAM));
496 MPM.addPass(Pass: createModuleToFunctionPassAdaptor(Pass: std::move(FPM)));
497 }
498
499 // A fifth function pass manager which invalidates one function first but
500 // uses only cached results.
501 int FunctionPassRunCount5 = 0;
502 int AnalyzedInstrCount5 = 0;
503 int AnalyzedFunctionCount5 = 0;
504 {
505 FunctionPassManager FPM;
506 FPM.addPass(Pass: TestInvalidationFunctionPass("f"));
507 FPM.addPass(Pass: TestFunctionPass(FunctionPassRunCount5, AnalyzedInstrCount5,
508 AnalyzedFunctionCount5, MAM,
509 /*OnlyUseCachedResults=*/true));
510 MPM.addPass(Pass: createModuleToFunctionPassAdaptor(Pass: std::move(FPM)));
511 }
512
513 MPM.run(IR&: *M, AM&: MAM);
514
515 // Validate module pass counters.
516 EXPECT_EQ(1, ModulePassRunCount);
517
518 // Validate all function pass counter sets are the same.
519 EXPECT_EQ(3, FunctionPassRunCount1);
520 EXPECT_EQ(5, AnalyzedInstrCount1);
521 EXPECT_EQ(0, AnalyzedFunctionCount1);
522 EXPECT_EQ(3, FunctionPassRunCount2);
523 EXPECT_EQ(5, AnalyzedInstrCount2);
524 EXPECT_EQ(0, AnalyzedFunctionCount2);
525 EXPECT_EQ(3, FunctionPassRunCount3);
526 EXPECT_EQ(5, AnalyzedInstrCount3);
527 EXPECT_EQ(0, AnalyzedFunctionCount3);
528 EXPECT_EQ(3, FunctionPassRunCount4);
529 EXPECT_EQ(5, AnalyzedInstrCount4);
530 EXPECT_EQ(9, AnalyzedFunctionCount4);
531 EXPECT_EQ(3, FunctionPassRunCount5);
532 EXPECT_EQ(2, AnalyzedInstrCount5); // Only 'g' and 'h' were cached.
533 EXPECT_EQ(9, AnalyzedFunctionCount5);
534
535 // Validate the analysis counters:
536 // first run over 3 functions, then module pass invalidates
537 // second run over 3 functions, nothing invalidates
538 // third run over 0 functions, but 1 function invalidated
539 // fourth run over 1 function
540 // fifth run invalidates 1 function first, but runs over 0 functions
541 EXPECT_EQ(7, FunctionAnalysisRuns);
542
543 EXPECT_EQ(1, ModuleAnalysisRuns);
544}
545
546// A customized pass manager that passes extra arguments through the
547// infrastructure.
548typedef AnalysisManager<Function, int> CustomizedAnalysisManager;
549typedef PassManager<Function, CustomizedAnalysisManager, int, int &>
550 CustomizedPassManager;
551
552class CustomizedAnalysis : public AnalysisInfoMixin<CustomizedAnalysis> {
553public:
554 struct Result {
555 Result(int I) : I(I) {}
556 int I;
557 };
558
559 Result run(Function &F, CustomizedAnalysisManager &AM, int I) {
560 return Result(I);
561 }
562
563private:
564 friend AnalysisInfoMixin<CustomizedAnalysis>;
565 static AnalysisKey Key;
566};
567
568AnalysisKey CustomizedAnalysis::Key;
569
570struct CustomizedPass : PassInfoMixin<CustomizedPass> {
571 std::function<void(CustomizedAnalysis::Result &, int &)> Callback;
572
573 template <typename CallbackT>
574 CustomizedPass(CallbackT Callback) : Callback(Callback) {}
575
576 PreservedAnalyses run(Function &F, CustomizedAnalysisManager &AM, int I,
577 int &O) {
578 Callback(AM.getResult<CustomizedAnalysis>(IR&: F, ExtraArgs: I), O);
579 return PreservedAnalyses::none();
580 }
581};
582
583TEST_F(PassManagerTest, CustomizedPassManagerArgs) {
584 CustomizedAnalysisManager AM;
585 AM.registerPass(PassBuilder: [&] { return CustomizedAnalysis(); });
586 PassInstrumentationCallbacks PIC;
587 AM.registerPass(PassBuilder: [&] { return PassInstrumentationAnalysis(&PIC); });
588
589 CustomizedPassManager PM;
590
591 // Add an instance of the customized pass that just accumulates the input
592 // after it is round-tripped through the analysis.
593 int Result = 0;
594 PM.addPass(
595 Pass: CustomizedPass([](CustomizedAnalysis::Result &R, int &O) { O += R.I; }));
596
597 // Run this over every function with the input of 42.
598 for (Function &F : *M)
599 PM.run(IR&: F, AM, ExtraArgs: 42, ExtraArgs&: Result);
600
601 // And ensure that we accumulated the correct result.
602 EXPECT_EQ(42 * (int)M->size(), Result);
603}
604
605/// A test analysis pass which caches in its result another analysis pass and
606/// uses it to serve queries. This requires the result to invalidate itself
607/// when its dependency is invalidated.
608struct TestIndirectFunctionAnalysis
609 : public AnalysisInfoMixin<TestIndirectFunctionAnalysis> {
610 struct Result {
611 Result(TestFunctionAnalysis::Result &FDep, TestModuleAnalysis::Result &MDep)
612 : FDep(FDep), MDep(MDep) {}
613 TestFunctionAnalysis::Result &FDep;
614 TestModuleAnalysis::Result &MDep;
615
616 bool invalidate(Function &F, const PreservedAnalyses &PA,
617 FunctionAnalysisManager::Invalidator &Inv) {
618 auto PAC = PA.getChecker<TestIndirectFunctionAnalysis>();
619 return !(PAC.preserved() ||
620 PAC.preservedSet<AllAnalysesOn<Function>>()) ||
621 Inv.invalidate<TestFunctionAnalysis>(IR&: F, PA);
622 }
623 };
624
625 TestIndirectFunctionAnalysis(int &Runs, ModuleAnalysisManager &MAM)
626 : Runs(Runs), MAM(MAM) {}
627
628 /// Run the analysis pass over the function and return a result.
629 Result run(Function &F, FunctionAnalysisManager &AM) {
630 ++Runs;
631 auto &FDep = AM.getResult<TestFunctionAnalysis>(IR&: F);
632 auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(IR&: F);
633 // For the test, we insist that the module analysis starts off in the
634 // cache. Getting a cached result that isn't stateless trigger an assert.
635 // Use MAM, for the purposes of this unittest.
636 auto &MDep = *MAM.getCachedResult<TestModuleAnalysis>(IR&: *F.getParent());
637 // And register the dependency as module analysis dependencies have to be
638 // pre-registered on the proxy.
639 MAMProxy.registerOuterAnalysisInvalidation<TestModuleAnalysis,
640 TestIndirectFunctionAnalysis>();
641 return Result(FDep, MDep);
642 }
643
644private:
645 friend AnalysisInfoMixin<TestIndirectFunctionAnalysis>;
646 static AnalysisKey Key;
647
648 int &Runs;
649 ModuleAnalysisManager &MAM;
650};
651
652AnalysisKey TestIndirectFunctionAnalysis::Key;
653
654/// A test analysis pass which chaches in its result the result from the above
655/// indirect analysis pass.
656///
657/// This allows us to ensure that whenever an analysis pass is invalidated due
658/// to dependencies (especially dependencies across IR units that trigger
659/// asynchronous invalidation) we correctly detect that this may in turn cause
660/// other analysis to be invalidated.
661struct TestDoublyIndirectFunctionAnalysis
662 : public AnalysisInfoMixin<TestDoublyIndirectFunctionAnalysis> {
663 struct Result {
664 Result(TestIndirectFunctionAnalysis::Result &IDep) : IDep(IDep) {}
665 TestIndirectFunctionAnalysis::Result &IDep;
666
667 bool invalidate(Function &F, const PreservedAnalyses &PA,
668 FunctionAnalysisManager::Invalidator &Inv) {
669 auto PAC = PA.getChecker<TestDoublyIndirectFunctionAnalysis>();
670 return !(PAC.preserved() ||
671 PAC.preservedSet<AllAnalysesOn<Function>>()) ||
672 Inv.invalidate<TestIndirectFunctionAnalysis>(IR&: F, PA);
673 }
674 };
675
676 TestDoublyIndirectFunctionAnalysis(int &Runs) : Runs(Runs) {}
677
678 /// Run the analysis pass over the function and return a result.
679 Result run(Function &F, FunctionAnalysisManager &AM) {
680 ++Runs;
681 auto &IDep = AM.getResult<TestIndirectFunctionAnalysis>(IR&: F);
682 return Result(IDep);
683 }
684
685private:
686 friend AnalysisInfoMixin<TestDoublyIndirectFunctionAnalysis>;
687 static AnalysisKey Key;
688
689 int &Runs;
690};
691
692AnalysisKey TestDoublyIndirectFunctionAnalysis::Key;
693
694struct LambdaPass : public PassInfoMixin<LambdaPass> {
695 using FuncT = std::function<PreservedAnalyses(Function &, FunctionAnalysisManager &)>;
696
697 LambdaPass(FuncT Func) : Func(std::move(Func)) {}
698
699 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
700 return Func(F, AM);
701 }
702
703 FuncT Func;
704};
705
706TEST_F(PassManagerTest, IndirectAnalysisInvalidation) {
707 FunctionAnalysisManager FAM;
708 ModuleAnalysisManager MAM;
709 int FunctionAnalysisRuns = 0, ModuleAnalysisRuns = 0,
710 IndirectAnalysisRuns = 0, DoublyIndirectAnalysisRuns = 0;
711 FAM.registerPass(PassBuilder: [&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
712 FAM.registerPass(
713 PassBuilder: [&] { return TestIndirectFunctionAnalysis(IndirectAnalysisRuns, MAM); });
714 FAM.registerPass(PassBuilder: [&] {
715 return TestDoublyIndirectFunctionAnalysis(DoublyIndirectAnalysisRuns);
716 });
717
718 MAM.registerPass(PassBuilder: [&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
719 MAM.registerPass(PassBuilder: [&] { return FunctionAnalysisManagerModuleProxy(FAM); });
720 FAM.registerPass(PassBuilder: [&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
721
722 PassInstrumentationCallbacks PIC;
723 MAM.registerPass(PassBuilder: [&] { return PassInstrumentationAnalysis(&PIC); });
724 FAM.registerPass(PassBuilder: [&] { return PassInstrumentationAnalysis(&PIC); });
725
726 int InstrCount = 0, FunctionCount = 0;
727 ModulePassManager MPM;
728 FunctionPassManager FPM;
729 // First just use the analysis to get the instruction count, and preserve
730 // everything.
731 FPM.addPass(Pass: LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {
732 auto &DoublyIndirectResult =
733 AM.getResult<TestDoublyIndirectFunctionAnalysis>(IR&: F);
734 auto &IndirectResult = DoublyIndirectResult.IDep;
735 InstrCount += IndirectResult.FDep.InstructionCount;
736 FunctionCount += IndirectResult.MDep.FunctionCount;
737 return PreservedAnalyses::all();
738 }));
739 // Next, invalidate
740 // - both analyses for "f",
741 // - just the underlying (indirect) analysis for "g", and
742 // - just the direct analysis for "h".
743 FPM.addPass(Pass: LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {
744 auto &DoublyIndirectResult =
745 AM.getResult<TestDoublyIndirectFunctionAnalysis>(IR&: F);
746 auto &IndirectResult = DoublyIndirectResult.IDep;
747 InstrCount += IndirectResult.FDep.InstructionCount;
748 FunctionCount += IndirectResult.MDep.FunctionCount;
749 auto PA = PreservedAnalyses::none();
750 if (F.getName() == "g")
751 PA.preserve<TestFunctionAnalysis>();
752 else if (F.getName() == "h")
753 PA.preserve<TestIndirectFunctionAnalysis>();
754 return PA;
755 }));
756 // Finally, use the analysis again on each function, forcing re-computation
757 // for all of them.
758 FPM.addPass(Pass: LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {
759 auto &DoublyIndirectResult =
760 AM.getResult<TestDoublyIndirectFunctionAnalysis>(IR&: F);
761 auto &IndirectResult = DoublyIndirectResult.IDep;
762 InstrCount += IndirectResult.FDep.InstructionCount;
763 FunctionCount += IndirectResult.MDep.FunctionCount;
764 return PreservedAnalyses::all();
765 }));
766
767 // Create a second function pass manager. This will cause the module-level
768 // invalidation to occur, which will force yet another invalidation of the
769 // indirect function-level analysis as the module analysis it depends on gets
770 // invalidated.
771 FunctionPassManager FPM2;
772 FPM2.addPass(Pass: LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {
773 auto &DoublyIndirectResult =
774 AM.getResult<TestDoublyIndirectFunctionAnalysis>(IR&: F);
775 auto &IndirectResult = DoublyIndirectResult.IDep;
776 InstrCount += IndirectResult.FDep.InstructionCount;
777 FunctionCount += IndirectResult.MDep.FunctionCount;
778 return PreservedAnalyses::all();
779 }));
780
781 // Add a requires pass to populate the module analysis and then our function
782 // pass pipeline.
783 MPM.addPass(Pass: RequireAnalysisPass<TestModuleAnalysis, Module>());
784 MPM.addPass(Pass: createModuleToFunctionPassAdaptor(Pass: std::move(FPM)));
785 // Now require the module analysis again (it will have been invalidated once)
786 // and then use it again from a function pass manager.
787 MPM.addPass(Pass: RequireAnalysisPass<TestModuleAnalysis, Module>());
788 MPM.addPass(Pass: createModuleToFunctionPassAdaptor(Pass: std::move(FPM2)));
789 MPM.run(IR&: *M, AM&: MAM);
790
791 // There are generally two possible runs for each of the three functions. But
792 // for one function, we only invalidate the indirect analysis so the base one
793 // only gets run five times.
794 EXPECT_EQ(5, FunctionAnalysisRuns);
795 // The module analysis pass should be run twice here.
796 EXPECT_EQ(2, ModuleAnalysisRuns);
797 // The indirect analysis is invalidated for each function (either directly or
798 // indirectly) and run twice for each.
799 EXPECT_EQ(9, IndirectAnalysisRuns);
800 EXPECT_EQ(9, DoublyIndirectAnalysisRuns);
801
802 // There are five instructions in the module and we add the count four
803 // times.
804 EXPECT_EQ(5 * 4, InstrCount);
805
806 // There are three functions and we count them four times for each of the
807 // three functions.
808 EXPECT_EQ(3 * 4 * 3, FunctionCount);
809}
810
811// Run SimplifyCFGPass that makes CFG changes and reports PreservedAnalyses
812// without CFGAnalyses. So the CFGChecker does not complain.
813TEST_F(PassManagerTest, FunctionPassCFGChecker) {
814 LLVMContext Context;
815 // SimplifyCFG changes this function to
816 // define void @foo {next: ret void}
817 auto M = parseIR(Context, IR: "define void @foo() {\n"
818 " br label %next\n"
819 "next:\n"
820 " br label %exit\n"
821 "exit:\n"
822 " ret void\n"
823 "}\n");
824
825 auto *F = M->getFunction(Name: "foo");
826 FunctionAnalysisManager FAM;
827 ModuleAnalysisManager MAM;
828 FunctionPassManager FPM;
829 PassInstrumentationCallbacks PIC;
830 StandardInstrumentations SI(M->getContext(), /*DebugLogging*/ true);
831 SI.registerCallbacks(PIC, MAM: &MAM);
832 MAM.registerPass(PassBuilder: [&] { return PassInstrumentationAnalysis(&PIC); });
833 MAM.registerPass(PassBuilder: [&] { return FunctionAnalysisManagerModuleProxy(FAM); });
834 FAM.registerPass(PassBuilder: [&] { return PassInstrumentationAnalysis(&PIC); });
835 FAM.registerPass(PassBuilder: [&] { return DominatorTreeAnalysis(); });
836 FAM.registerPass(PassBuilder: [&] { return AssumptionAnalysis(); });
837 FAM.registerPass(PassBuilder: [&] { return TargetIRAnalysis(); });
838
839 FPM.addPass(Pass: SimplifyCFGPass());
840 FPM.run(IR&: *F, AM&: FAM);
841}
842
843// FunctionPass that manually invalidates analyses and always returns
844// PreservedAnalyses::all().
845struct TestSimplifyCFGInvalidatingAnalysisPass
846 : PassInfoMixin<TestSimplifyCFGInvalidatingAnalysisPass> {
847 PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {
848 // Run SimplifyCFG and if it changes CFG then invalidate the CFG analysis.
849 // This allows to return PreserveAnalysis::all().
850 PreservedAnalyses PA = CFGSimplifier.run(F, AM&: FAM);
851 FAM.invalidate(IR&: F, PA);
852 return PreservedAnalyses::all();
853 }
854
855 SimplifyCFGPass CFGSimplifier;
856};
857
858// Run TestSimplifyCFGInvalidatingAnalysisPass which changes CFG by running
859// SimplifyCFGPass then manually invalidates analyses and always returns
860// PreservedAnalyses::all(). CFGChecker does not complain because it resets
861// its saved CFG snapshot when the analyses are invalidated manually.
862TEST_F(PassManagerTest, FunctionPassCFGCheckerInvalidateAnalysis) {
863 LLVMContext Context;
864 // SimplifyCFG changes this function to
865 // define void @foo {next: ret void}
866 auto M = parseIR(Context, IR: "define void @foo() {\n"
867 " br label %next\n"
868 "next:\n"
869 " br label %exit\n"
870 "exit:\n"
871 " ret void\n"
872 "}\n");
873
874 auto *F = M->getFunction(Name: "foo");
875 FunctionAnalysisManager FAM;
876 ModuleAnalysisManager MAM;
877 FunctionPassManager FPM;
878 PassInstrumentationCallbacks PIC;
879 StandardInstrumentations SI(M->getContext(), /*DebugLogging*/ true);
880 SI.registerCallbacks(PIC, MAM: &MAM);
881 MAM.registerPass(PassBuilder: [&] { return FunctionAnalysisManagerModuleProxy(FAM); });
882 MAM.registerPass(PassBuilder: [&] { return PassInstrumentationAnalysis(&PIC); });
883 FAM.registerPass(PassBuilder: [&] { return PassInstrumentationAnalysis(&PIC); });
884 FAM.registerPass(PassBuilder: [&] { return DominatorTreeAnalysis(); });
885 FAM.registerPass(PassBuilder: [&] { return AssumptionAnalysis(); });
886 FAM.registerPass(PassBuilder: [&] { return TargetIRAnalysis(); });
887
888 FPM.addPass(Pass: TestSimplifyCFGInvalidatingAnalysisPass());
889 FPM.run(IR&: *F, AM&: FAM);
890}
891
892// Wrap a FunctionPassManager running SimplifyCFG pass with another
893// FunctionPassManager.
894struct TestSimplifyCFGWrapperPass : PassInfoMixin<TestSimplifyCFGWrapperPass> {
895 TestSimplifyCFGWrapperPass(FunctionPassManager &InnerPM) : InnerPM(InnerPM) {}
896
897 PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {
898 // Here we simulate exactly what FunctionPassManager::run() does but
899 // instead of running all passes from InnerPM.Passes we run them in bulk
900 // by calling InnerPM.run().
901 PreservedAnalyses PA = PreservedAnalyses::all();
902 PassInstrumentation PI = FAM.getResult<PassInstrumentationAnalysis>(IR&: F);
903
904 if (!PI.runBeforePass<Function>(Pass: InnerPM, IR: F))
905 return PreservedAnalyses::all();
906
907 PreservedAnalyses PassPA = InnerPM.run(IR&: F, AM&: FAM);
908 PI.runAfterPass(Pass: InnerPM, IR: F, PA: PassPA);
909 FAM.invalidate(IR&: F, PA: PassPA);
910 PA.intersect(Arg: PassPA);
911 PA.preserveSet<AllAnalysesOn<Function>>();
912 return PA;
913 }
914
915 FunctionPassManager &InnerPM;
916};
917
918// Run TestSimplifyCFGWrapperPass which simulates behavior of
919// FunctionPassManager::run() except that it runs all passes at once by calling
920// an inner pass manager's passes with PassManager::run(). This is how one pass
921// manager is expected to wrap another pass manager.
922// SimplifyCFGPass, which is called by the inner pass manager, changes the CFG.
923// The CFGChecker's AfterPassCallback, run right after SimplifyCFGPass, does not
924// complain because CFGAnalyses is not in the PreservedAnalises set returned by
925// SimplifyCFGPass. Then the CFG analysis is invalidated by the analysis manager
926// according to the PreservedAnalises set. Further calls to CFGChecker's
927// AfterPassCallback see that all analyses for the current function are
928// preserved but there is no CFG snapshot available (i.e.
929// AM.getCachedResult<PreservedCFGCheckerAnalysis>(F) returns nullptr).
930TEST_F(PassManagerTest, FunctionPassCFGCheckerWrapped) {
931 LLVMContext Context;
932 // SimplifyCFG changes this function to
933 // define void @foo {next: ret void}
934 auto M = parseIR(Context, IR: "define void @foo() {\n"
935 " br label %next\n"
936 "next:\n"
937 " br label %exit\n"
938 "exit:\n"
939 " ret void\n"
940 "}\n");
941
942 auto *F = M->getFunction(Name: "foo");
943 FunctionAnalysisManager FAM;
944 ModuleAnalysisManager MAM;
945 FunctionPassManager FPM;
946 PassInstrumentationCallbacks PIC;
947 StandardInstrumentations SI(M->getContext(), /*DebugLogging*/ true);
948 SI.registerCallbacks(PIC, MAM: &MAM);
949 MAM.registerPass(PassBuilder: [&] { return FunctionAnalysisManagerModuleProxy(FAM); });
950 MAM.registerPass(PassBuilder: [&] { return PassInstrumentationAnalysis(&PIC); });
951 FAM.registerPass(PassBuilder: [&] { return PassInstrumentationAnalysis(&PIC); });
952 FAM.registerPass(PassBuilder: [&] { return DominatorTreeAnalysis(); });
953 FAM.registerPass(PassBuilder: [&] { return AssumptionAnalysis(); });
954 FAM.registerPass(PassBuilder: [&] { return TargetIRAnalysis(); });
955
956 FunctionPassManager InnerFPM;
957 InnerFPM.addPass(Pass: SimplifyCFGPass());
958
959 FPM.addPass(Pass: TestSimplifyCFGWrapperPass(InnerFPM));
960 FPM.run(IR&: *F, AM&: FAM);
961}
962
963#ifdef EXPENSIVE_CHECKS
964
965struct WrongFunctionPass : PassInfoMixin<WrongFunctionPass> {
966 PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {
967 F.getEntryBlock().begin()->eraseFromParent();
968 return PreservedAnalyses::all();
969 }
970 static StringRef name() { return "WrongFunctionPass"; }
971};
972
973TEST_F(PassManagerTest, FunctionPassMissedFunctionAnalysisInvalidation) {
974 LLVMContext Context;
975 auto M = parseIR(Context, "define void @foo() {\n"
976 " %a = add i32 0, 0\n"
977 " ret void\n"
978 "}\n");
979
980 FunctionAnalysisManager FAM;
981 ModuleAnalysisManager MAM;
982 PassInstrumentationCallbacks PIC;
983 StandardInstrumentations SI(M->getContext(), /*DebugLogging*/ false);
984 SI.registerCallbacks(PIC, &MAM);
985 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
986 MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });
987 FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });
988 FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
989
990 FunctionPassManager FPM;
991 FPM.addPass(WrongFunctionPass());
992
993 auto *F = M->getFunction("foo");
994 EXPECT_DEATH(FPM.run(*F, FAM), "Function @foo changed by WrongFunctionPass without invalidating analyses");
995}
996
997struct WrongModulePass : PassInfoMixin<WrongModulePass> {
998 PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM) {
999 for (Function &F : M)
1000 F.getEntryBlock().begin()->eraseFromParent();
1001
1002 PreservedAnalyses PA;
1003 PA.preserveSet<AllAnalysesOn<Function>>();
1004 PA.preserve<FunctionAnalysisManagerModuleProxy>();
1005 return PA;
1006 }
1007 static StringRef name() { return "WrongModulePass"; }
1008};
1009
1010TEST_F(PassManagerTest, ModulePassMissedFunctionAnalysisInvalidation) {
1011 LLVMContext Context;
1012 auto M = parseIR(Context, "define void @foo() {\n"
1013 " %a = add i32 0, 0\n"
1014 " ret void\n"
1015 "}\n");
1016
1017 FunctionAnalysisManager FAM;
1018 ModuleAnalysisManager MAM;
1019 PassInstrumentationCallbacks PIC;
1020 StandardInstrumentations SI(M->getContext(), /*DebugLogging*/ false);
1021 SI.registerCallbacks(PIC, &MAM);
1022 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
1023 MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });
1024 FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });
1025 FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
1026
1027 ModulePassManager MPM;
1028 MPM.addPass(WrongModulePass());
1029
1030 EXPECT_DEATH(
1031 MPM.run(*M, MAM),
1032 "Function @foo changed by WrongModulePass without invalidating analyses");
1033}
1034
1035struct WrongModulePass2 : PassInfoMixin<WrongModulePass2> {
1036 PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM) {
1037 for (Function &F : M)
1038 F.getEntryBlock().begin()->eraseFromParent();
1039
1040 PreservedAnalyses PA;
1041 PA.preserveSet<AllAnalysesOn<Module>>();
1042 PA.abandon<FunctionAnalysisManagerModuleProxy>();
1043 return PA;
1044 }
1045 static StringRef name() { return "WrongModulePass2"; }
1046};
1047
1048TEST_F(PassManagerTest, ModulePassMissedModuleAnalysisInvalidation) {
1049 LLVMContext Context;
1050 auto M = parseIR(Context, "define void @foo() {\n"
1051 " %a = add i32 0, 0\n"
1052 " ret void\n"
1053 "}\n");
1054
1055 FunctionAnalysisManager FAM;
1056 ModuleAnalysisManager MAM;
1057 PassInstrumentationCallbacks PIC;
1058 StandardInstrumentations SI(M->getContext(), /*DebugLogging*/ false);
1059 SI.registerCallbacks(PIC, &MAM);
1060 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
1061 MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });
1062 FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });
1063 FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
1064
1065 ModulePassManager MPM;
1066 MPM.addPass(WrongModulePass2());
1067
1068 EXPECT_DEATH(
1069 MPM.run(*M, MAM),
1070 "Module changed by WrongModulePass2 without invalidating analyses");
1071}
1072
1073#endif
1074}
1075

source code of llvm/unittests/IR/PassManagerTest.cpp