1 //===- AnalysisManagerTest.cpp - AnalysisManager unit tests ---------------===//
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 "mlir/Pass/AnalysisManager.h"
10 #include "mlir/Dialect/Func/IR/FuncOps.h"
11 #include "mlir/IR/Builders.h"
12 #include "mlir/IR/BuiltinOps.h"
13 #include "mlir/Pass/Pass.h"
14 #include "mlir/Pass/PassManager.h"
15 #include "gtest/gtest.h"
18 using namespace mlir::detail
;
21 /// Minimal class definitions for two analyses.
23 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(MyAnalysis
)
25 MyAnalysis(Operation
*) {}
27 struct OtherAnalysis
{
28 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(OtherAnalysis
)
30 OtherAnalysis(Operation
*) {}
32 struct OpSpecificAnalysis
{
33 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(OpSpecificAnalysis
)
35 OpSpecificAnalysis(ModuleOp
) {}
38 TEST(AnalysisManagerTest
, FineGrainModuleAnalysisPreservation
) {
41 // Test fine grain invalidation of the module analysis manager.
42 OwningOpRef
<ModuleOp
> module(ModuleOp::create(UnknownLoc::get(&context
)));
43 ModuleAnalysisManager
mam(*module
, /*passInstrumentor=*/nullptr);
44 AnalysisManager am
= mam
;
46 // Query two different analyses, but only preserve one before invalidating.
47 am
.getAnalysis
<MyAnalysis
>();
48 am
.getAnalysis
<OtherAnalysis
>();
50 detail::PreservedAnalyses pa
;
51 pa
.preserve
<MyAnalysis
>();
54 // Check that only MyAnalysis is preserved.
55 EXPECT_TRUE(am
.getCachedAnalysis
<MyAnalysis
>().has_value());
56 EXPECT_FALSE(am
.getCachedAnalysis
<OtherAnalysis
>().has_value());
59 TEST(AnalysisManagerTest
, FineGrainFunctionAnalysisPreservation
) {
61 context
.loadDialect
<func::FuncDialect
>();
62 Builder
builder(&context
);
64 // Create a function and a module.
65 OwningOpRef
<ModuleOp
> module(ModuleOp::create(UnknownLoc::get(&context
)));
67 func::FuncOp::create(builder
.getUnknownLoc(), "foo",
68 builder
.getFunctionType(std::nullopt
, std::nullopt
));
70 module
->push_back(func1
);
72 // Test fine grain invalidation of the function analysis manager.
73 ModuleAnalysisManager
mam(*module
, /*passInstrumentor=*/nullptr);
74 AnalysisManager am
= mam
;
75 AnalysisManager fam
= am
.nest(func1
);
77 // Query two different analyses, but only preserve one before invalidating.
78 fam
.getAnalysis
<MyAnalysis
>();
79 fam
.getAnalysis
<OtherAnalysis
>();
81 detail::PreservedAnalyses pa
;
82 pa
.preserve
<MyAnalysis
>();
85 // Check that only MyAnalysis is preserved.
86 EXPECT_TRUE(fam
.getCachedAnalysis
<MyAnalysis
>().has_value());
87 EXPECT_FALSE(fam
.getCachedAnalysis
<OtherAnalysis
>().has_value());
90 TEST(AnalysisManagerTest
, FineGrainChildFunctionAnalysisPreservation
) {
92 context
.loadDialect
<func::FuncDialect
>();
93 Builder
builder(&context
);
95 // Create a function and a module.
96 OwningOpRef
<ModuleOp
> module(ModuleOp::create(UnknownLoc::get(&context
)));
98 func::FuncOp::create(builder
.getUnknownLoc(), "foo",
99 builder
.getFunctionType(std::nullopt
, std::nullopt
));
101 module
->push_back(func1
);
103 // Test fine grain invalidation of a function analysis from within a module
105 ModuleAnalysisManager
mam(*module
, /*passInstrumentor=*/nullptr);
106 AnalysisManager am
= mam
;
108 // Check that the analysis cache is initially empty.
109 EXPECT_FALSE(am
.getCachedChildAnalysis
<MyAnalysis
>(func1
).has_value());
111 // Query two different analyses, but only preserve one before invalidating.
112 am
.getChildAnalysis
<MyAnalysis
>(func1
);
113 am
.getChildAnalysis
<OtherAnalysis
>(func1
);
115 detail::PreservedAnalyses pa
;
116 pa
.preserve
<MyAnalysis
>();
119 // Check that only MyAnalysis is preserved.
120 EXPECT_TRUE(am
.getCachedChildAnalysis
<MyAnalysis
>(func1
).has_value());
121 EXPECT_FALSE(am
.getCachedChildAnalysis
<OtherAnalysis
>(func1
).has_value());
124 /// Test analyses with custom invalidation logic.
125 struct TestAnalysisSet
{
126 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestAnalysisSet
)
129 struct CustomInvalidatingAnalysis
{
130 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(CustomInvalidatingAnalysis
)
132 CustomInvalidatingAnalysis(Operation
*) {}
134 bool isInvalidated(const AnalysisManager::PreservedAnalyses
&pa
) {
135 return !pa
.isPreserved
<TestAnalysisSet
>();
139 TEST(AnalysisManagerTest
, CustomInvalidation
) {
141 Builder
builder(&context
);
143 // Create a function and a module.
144 OwningOpRef
<ModuleOp
> module(ModuleOp::create(UnknownLoc::get(&context
)));
145 ModuleAnalysisManager
mam(*module
, /*passInstrumentor=*/nullptr);
146 AnalysisManager am
= mam
;
148 detail::PreservedAnalyses pa
;
150 // Check that the analysis is invalidated properly.
151 am
.getAnalysis
<CustomInvalidatingAnalysis
>();
153 EXPECT_FALSE(am
.getCachedAnalysis
<CustomInvalidatingAnalysis
>().has_value());
155 // Check that the analysis is preserved properly.
156 am
.getAnalysis
<CustomInvalidatingAnalysis
>();
157 pa
.preserve
<TestAnalysisSet
>();
159 EXPECT_TRUE(am
.getCachedAnalysis
<CustomInvalidatingAnalysis
>().has_value());
162 TEST(AnalysisManagerTest
, OpSpecificAnalysis
) {
166 OwningOpRef
<ModuleOp
> module(ModuleOp::create(UnknownLoc::get(&context
)));
167 ModuleAnalysisManager
mam(*module
, /*passInstrumentor=*/nullptr);
168 AnalysisManager am
= mam
;
170 // Query the op specific analysis for the module and verify that its cached.
171 am
.getAnalysis
<OpSpecificAnalysis
, ModuleOp
>();
172 EXPECT_TRUE(am
.getCachedAnalysis
<OpSpecificAnalysis
>().has_value());
175 struct AnalysisWithDependency
{
176 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(AnalysisWithDependency
)
178 AnalysisWithDependency(Operation
*, AnalysisManager
&am
) {
179 am
.getAnalysis
<MyAnalysis
>();
182 bool isInvalidated(const AnalysisManager::PreservedAnalyses
&pa
) {
183 return !pa
.isPreserved
<AnalysisWithDependency
>() ||
184 !pa
.isPreserved
<MyAnalysis
>();
188 TEST(AnalysisManagerTest
, DependentAnalysis
) {
192 OwningOpRef
<ModuleOp
> module(ModuleOp::create(UnknownLoc::get(&context
)));
193 ModuleAnalysisManager
mam(*module
, /*passInstrumentor=*/nullptr);
194 AnalysisManager am
= mam
;
196 am
.getAnalysis
<AnalysisWithDependency
>();
197 EXPECT_TRUE(am
.getCachedAnalysis
<AnalysisWithDependency
>().has_value());
198 EXPECT_TRUE(am
.getCachedAnalysis
<MyAnalysis
>().has_value());
200 detail::PreservedAnalyses pa
;
201 pa
.preserve
<AnalysisWithDependency
>();
204 EXPECT_FALSE(am
.getCachedAnalysis
<AnalysisWithDependency
>().has_value());
205 EXPECT_FALSE(am
.getCachedAnalysis
<MyAnalysis
>().has_value());
208 struct AnalysisWithNestedDependency
{
209 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(AnalysisWithNestedDependency
)
211 AnalysisWithNestedDependency(Operation
*, AnalysisManager
&am
) {
212 am
.getAnalysis
<AnalysisWithDependency
>();
215 bool isInvalidated(const AnalysisManager::PreservedAnalyses
&pa
) {
216 return !pa
.isPreserved
<AnalysisWithNestedDependency
>() ||
217 !pa
.isPreserved
<AnalysisWithDependency
>();
221 TEST(AnalysisManagerTest
, NestedDependentAnalysis
) {
225 OwningOpRef
<ModuleOp
> module(ModuleOp::create(UnknownLoc::get(&context
)));
226 ModuleAnalysisManager
mam(*module
, /*passInstrumentor=*/nullptr);
227 AnalysisManager am
= mam
;
229 am
.getAnalysis
<AnalysisWithNestedDependency
>();
230 EXPECT_TRUE(am
.getCachedAnalysis
<AnalysisWithNestedDependency
>().has_value());
231 EXPECT_TRUE(am
.getCachedAnalysis
<AnalysisWithDependency
>().has_value());
232 EXPECT_TRUE(am
.getCachedAnalysis
<MyAnalysis
>().has_value());
234 detail::PreservedAnalyses pa
;
235 pa
.preserve
<AnalysisWithDependency
>();
236 pa
.preserve
<AnalysisWithNestedDependency
>();
240 am
.getCachedAnalysis
<AnalysisWithNestedDependency
>().has_value());
241 EXPECT_FALSE(am
.getCachedAnalysis
<AnalysisWithDependency
>().has_value());
242 EXPECT_FALSE(am
.getCachedAnalysis
<MyAnalysis
>().has_value());
245 struct AnalysisWith2Ctors
{
246 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(AnalysisWith2Ctors
)
248 AnalysisWith2Ctors(Operation
*) { ctor1called
= true; }
250 AnalysisWith2Ctors(Operation
*, AnalysisManager
&) { ctor2called
= true; }
252 bool ctor1called
= false;
253 bool ctor2called
= false;
256 TEST(AnalysisManagerTest
, DependentAnalysis2Ctors
) {
260 OwningOpRef
<ModuleOp
> module(ModuleOp::create(UnknownLoc::get(&context
)));
261 ModuleAnalysisManager
mam(*module
, /*passInstrumentor=*/nullptr);
262 AnalysisManager am
= mam
;
264 auto &an
= am
.getAnalysis
<AnalysisWith2Ctors
>();
265 EXPECT_FALSE(an
.ctor1called
);
266 EXPECT_TRUE(an
.ctor2called
);