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