1 //===- AnalysisManagerTest.cpp - AnalysisManager unit 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 "mlir/Pass/AnalysisManager.h"
10 #include "mlir/IR/Builders.h"
11 #include "mlir/IR/Function.h"
12 #include "mlir/Pass/Pass.h"
13 #include "mlir/Pass/PassManager.h"
14 #include "gtest/gtest.h"
15 
16 using namespace mlir;
17 using namespace mlir::detail;
18 
19 namespace {
20 /// Minimal class definitions for two analyses.
21 struct MyAnalysis {
22   MyAnalysis(Operation *) {}
23 };
24 struct OtherAnalysis {
25   OtherAnalysis(Operation *) {}
26 };
27 struct OpSpecificAnalysis {
28   OpSpecificAnalysis(ModuleOp) {}
29 };
30 
31 TEST(AnalysisManagerTest, FineGrainModuleAnalysisPreservation) {
32   MLIRContext context;
33 
34   // Test fine grain invalidation of the module analysis manager.
35   OwningModuleRef module(ModuleOp::create(UnknownLoc::get(&context)));
36   ModuleAnalysisManager mam(*module, /*passInstrumentor=*/nullptr);
37   AnalysisManager am = mam;
38 
39   // Query two different analyses, but only preserve one before invalidating.
40   am.getAnalysis<MyAnalysis>();
41   am.getAnalysis<OtherAnalysis>();
42 
43   detail::PreservedAnalyses pa;
44   pa.preserve<MyAnalysis>();
45   am.invalidate(pa);
46 
47   // Check that only MyAnalysis is preserved.
48   EXPECT_TRUE(am.getCachedAnalysis<MyAnalysis>().hasValue());
49   EXPECT_FALSE(am.getCachedAnalysis<OtherAnalysis>().hasValue());
50 }
51 
52 TEST(AnalysisManagerTest, FineGrainFunctionAnalysisPreservation) {
53   MLIRContext context;
54   Builder builder(&context);
55 
56   // Create a function and a module.
57   OwningModuleRef module(ModuleOp::create(UnknownLoc::get(&context)));
58   FuncOp func1 =
59       FuncOp::create(builder.getUnknownLoc(), "foo",
60                      builder.getFunctionType(llvm::None, llvm::None));
61   module->push_back(func1);
62 
63   // Test fine grain invalidation of the function analysis manager.
64   ModuleAnalysisManager mam(*module, /*passInstrumentor=*/nullptr);
65   AnalysisManager am = mam;
66   AnalysisManager fam = am.nest(func1);
67 
68   // Query two different analyses, but only preserve one before invalidating.
69   fam.getAnalysis<MyAnalysis>();
70   fam.getAnalysis<OtherAnalysis>();
71 
72   detail::PreservedAnalyses pa;
73   pa.preserve<MyAnalysis>();
74   fam.invalidate(pa);
75 
76   // Check that only MyAnalysis is preserved.
77   EXPECT_TRUE(fam.getCachedAnalysis<MyAnalysis>().hasValue());
78   EXPECT_FALSE(fam.getCachedAnalysis<OtherAnalysis>().hasValue());
79 }
80 
81 TEST(AnalysisManagerTest, FineGrainChildFunctionAnalysisPreservation) {
82   MLIRContext context;
83   Builder builder(&context);
84 
85   // Create a function and a module.
86   OwningModuleRef module(ModuleOp::create(UnknownLoc::get(&context)));
87   FuncOp func1 =
88       FuncOp::create(builder.getUnknownLoc(), "foo",
89                      builder.getFunctionType(llvm::None, llvm::None));
90   module->push_back(func1);
91 
92   // Test fine grain invalidation of a function analysis from within a module
93   // analysis manager.
94   ModuleAnalysisManager mam(*module, /*passInstrumentor=*/nullptr);
95   AnalysisManager am = mam;
96 
97   // Check that the analysis cache is initially empty.
98   EXPECT_FALSE(am.getCachedChildAnalysis<MyAnalysis>(func1).hasValue());
99 
100   // Query two different analyses, but only preserve one before invalidating.
101   am.getChildAnalysis<MyAnalysis>(func1);
102   am.getChildAnalysis<OtherAnalysis>(func1);
103 
104   detail::PreservedAnalyses pa;
105   pa.preserve<MyAnalysis>();
106   am.invalidate(pa);
107 
108   // Check that only MyAnalysis is preserved.
109   EXPECT_TRUE(am.getCachedChildAnalysis<MyAnalysis>(func1).hasValue());
110   EXPECT_FALSE(am.getCachedChildAnalysis<OtherAnalysis>(func1).hasValue());
111 }
112 
113 /// Test analyses with custom invalidation logic.
114 struct TestAnalysisSet {};
115 
116 struct CustomInvalidatingAnalysis {
117   CustomInvalidatingAnalysis(Operation *) {}
118 
119   bool isInvalidated(const AnalysisManager::PreservedAnalyses &pa) {
120     return !pa.isPreserved<TestAnalysisSet>();
121   }
122 };
123 
124 TEST(AnalysisManagerTest, CustomInvalidation) {
125   MLIRContext context;
126   Builder builder(&context);
127 
128   // Create a function and a module.
129   OwningModuleRef module(ModuleOp::create(UnknownLoc::get(&context)));
130   ModuleAnalysisManager mam(*module, /*passInstrumentor=*/nullptr);
131   AnalysisManager am = mam;
132 
133   detail::PreservedAnalyses pa;
134 
135   // Check that the analysis is invalidated properly.
136   am.getAnalysis<CustomInvalidatingAnalysis>();
137   am.invalidate(pa);
138   EXPECT_FALSE(am.getCachedAnalysis<CustomInvalidatingAnalysis>().hasValue());
139 
140   // Check that the analysis is preserved properly.
141   am.getAnalysis<CustomInvalidatingAnalysis>();
142   pa.preserve<TestAnalysisSet>();
143   am.invalidate(pa);
144   EXPECT_TRUE(am.getCachedAnalysis<CustomInvalidatingAnalysis>().hasValue());
145 }
146 
147 TEST(AnalysisManagerTest, OpSpecificAnalysis) {
148   MLIRContext context;
149 
150   // Create a module.
151   OwningModuleRef module(ModuleOp::create(UnknownLoc::get(&context)));
152   ModuleAnalysisManager mam(*module, /*passInstrumentor=*/nullptr);
153   AnalysisManager am = mam;
154 
155   // Query the op specific analysis for the module and verify that its cached.
156   am.getAnalysis<OpSpecificAnalysis, ModuleOp>();
157   EXPECT_TRUE(am.getCachedAnalysis<OpSpecificAnalysis>().hasValue());
158 }
159 
160 } // end namespace
161