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/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" 16 17 using namespace mlir; 18 using namespace mlir::detail; 19 20 namespace { 21 /// Minimal class definitions for two analyses. 22 struct MyAnalysis { 23 MyAnalysis(Operation *) {} 24 }; 25 struct OtherAnalysis { 26 OtherAnalysis(Operation *) {} 27 }; 28 struct OpSpecificAnalysis { 29 OpSpecificAnalysis(ModuleOp) {} 30 }; 31 32 TEST(AnalysisManagerTest, FineGrainModuleAnalysisPreservation) { 33 MLIRContext context; 34 35 // Test fine grain invalidation of the module analysis manager. 36 OwningOpRef<ModuleOp> module(ModuleOp::create(UnknownLoc::get(&context))); 37 ModuleAnalysisManager mam(*module, /*passInstrumentor=*/nullptr); 38 AnalysisManager am = mam; 39 40 // Query two different analyses, but only preserve one before invalidating. 41 am.getAnalysis<MyAnalysis>(); 42 am.getAnalysis<OtherAnalysis>(); 43 44 detail::PreservedAnalyses pa; 45 pa.preserve<MyAnalysis>(); 46 am.invalidate(pa); 47 48 // Check that only MyAnalysis is preserved. 49 EXPECT_TRUE(am.getCachedAnalysis<MyAnalysis>().hasValue()); 50 EXPECT_FALSE(am.getCachedAnalysis<OtherAnalysis>().hasValue()); 51 } 52 53 TEST(AnalysisManagerTest, FineGrainFunctionAnalysisPreservation) { 54 MLIRContext context; 55 context.loadDialect<func::FuncDialect>(); 56 Builder builder(&context); 57 58 // Create a function and a module. 59 OwningOpRef<ModuleOp> module(ModuleOp::create(UnknownLoc::get(&context))); 60 FuncOp func1 = 61 FuncOp::create(builder.getUnknownLoc(), "foo", 62 builder.getFunctionType(llvm::None, llvm::None)); 63 func1.setPrivate(); 64 module->push_back(func1); 65 66 // Test fine grain invalidation of the function analysis manager. 67 ModuleAnalysisManager mam(*module, /*passInstrumentor=*/nullptr); 68 AnalysisManager am = mam; 69 AnalysisManager fam = am.nest(func1); 70 71 // Query two different analyses, but only preserve one before invalidating. 72 fam.getAnalysis<MyAnalysis>(); 73 fam.getAnalysis<OtherAnalysis>(); 74 75 detail::PreservedAnalyses pa; 76 pa.preserve<MyAnalysis>(); 77 fam.invalidate(pa); 78 79 // Check that only MyAnalysis is preserved. 80 EXPECT_TRUE(fam.getCachedAnalysis<MyAnalysis>().hasValue()); 81 EXPECT_FALSE(fam.getCachedAnalysis<OtherAnalysis>().hasValue()); 82 } 83 84 TEST(AnalysisManagerTest, FineGrainChildFunctionAnalysisPreservation) { 85 MLIRContext context; 86 context.loadDialect<func::FuncDialect>(); 87 Builder builder(&context); 88 89 // Create a function and a module. 90 OwningOpRef<ModuleOp> module(ModuleOp::create(UnknownLoc::get(&context))); 91 FuncOp func1 = 92 FuncOp::create(builder.getUnknownLoc(), "foo", 93 builder.getFunctionType(llvm::None, llvm::None)); 94 func1.setPrivate(); 95 module->push_back(func1); 96 97 // Test fine grain invalidation of a function analysis from within a module 98 // analysis manager. 99 ModuleAnalysisManager mam(*module, /*passInstrumentor=*/nullptr); 100 AnalysisManager am = mam; 101 102 // Check that the analysis cache is initially empty. 103 EXPECT_FALSE(am.getCachedChildAnalysis<MyAnalysis>(func1).hasValue()); 104 105 // Query two different analyses, but only preserve one before invalidating. 106 am.getChildAnalysis<MyAnalysis>(func1); 107 am.getChildAnalysis<OtherAnalysis>(func1); 108 109 detail::PreservedAnalyses pa; 110 pa.preserve<MyAnalysis>(); 111 am.invalidate(pa); 112 113 // Check that only MyAnalysis is preserved. 114 EXPECT_TRUE(am.getCachedChildAnalysis<MyAnalysis>(func1).hasValue()); 115 EXPECT_FALSE(am.getCachedChildAnalysis<OtherAnalysis>(func1).hasValue()); 116 } 117 118 /// Test analyses with custom invalidation logic. 119 struct TestAnalysisSet {}; 120 121 struct CustomInvalidatingAnalysis { 122 CustomInvalidatingAnalysis(Operation *) {} 123 124 bool isInvalidated(const AnalysisManager::PreservedAnalyses &pa) { 125 return !pa.isPreserved<TestAnalysisSet>(); 126 } 127 }; 128 129 TEST(AnalysisManagerTest, CustomInvalidation) { 130 MLIRContext context; 131 Builder builder(&context); 132 133 // Create a function and a module. 134 OwningOpRef<ModuleOp> module(ModuleOp::create(UnknownLoc::get(&context))); 135 ModuleAnalysisManager mam(*module, /*passInstrumentor=*/nullptr); 136 AnalysisManager am = mam; 137 138 detail::PreservedAnalyses pa; 139 140 // Check that the analysis is invalidated properly. 141 am.getAnalysis<CustomInvalidatingAnalysis>(); 142 am.invalidate(pa); 143 EXPECT_FALSE(am.getCachedAnalysis<CustomInvalidatingAnalysis>().hasValue()); 144 145 // Check that the analysis is preserved properly. 146 am.getAnalysis<CustomInvalidatingAnalysis>(); 147 pa.preserve<TestAnalysisSet>(); 148 am.invalidate(pa); 149 EXPECT_TRUE(am.getCachedAnalysis<CustomInvalidatingAnalysis>().hasValue()); 150 } 151 152 TEST(AnalysisManagerTest, OpSpecificAnalysis) { 153 MLIRContext context; 154 155 // Create a module. 156 OwningOpRef<ModuleOp> module(ModuleOp::create(UnknownLoc::get(&context))); 157 ModuleAnalysisManager mam(*module, /*passInstrumentor=*/nullptr); 158 AnalysisManager am = mam; 159 160 // Query the op specific analysis for the module and verify that its cached. 161 am.getAnalysis<OpSpecificAnalysis, ModuleOp>(); 162 EXPECT_TRUE(am.getCachedAnalysis<OpSpecificAnalysis>().hasValue()); 163 } 164 165 struct AnalysisWithDependency { 166 AnalysisWithDependency(Operation *, AnalysisManager &am) { 167 am.getAnalysis<MyAnalysis>(); 168 } 169 170 bool isInvalidated(const AnalysisManager::PreservedAnalyses &pa) { 171 return !pa.isPreserved<AnalysisWithDependency>() || 172 !pa.isPreserved<MyAnalysis>(); 173 } 174 }; 175 176 TEST(AnalysisManagerTest, DependentAnalysis) { 177 MLIRContext context; 178 179 // Create a module. 180 OwningOpRef<ModuleOp> module(ModuleOp::create(UnknownLoc::get(&context))); 181 ModuleAnalysisManager mam(*module, /*passInstrumentor=*/nullptr); 182 AnalysisManager am = mam; 183 184 am.getAnalysis<AnalysisWithDependency>(); 185 EXPECT_TRUE(am.getCachedAnalysis<AnalysisWithDependency>().hasValue()); 186 EXPECT_TRUE(am.getCachedAnalysis<MyAnalysis>().hasValue()); 187 188 detail::PreservedAnalyses pa; 189 pa.preserve<AnalysisWithDependency>(); 190 am.invalidate(pa); 191 192 EXPECT_FALSE(am.getCachedAnalysis<AnalysisWithDependency>().hasValue()); 193 EXPECT_FALSE(am.getCachedAnalysis<MyAnalysis>().hasValue()); 194 } 195 196 struct AnalysisWithNestedDependency { 197 AnalysisWithNestedDependency(Operation *, AnalysisManager &am) { 198 am.getAnalysis<AnalysisWithDependency>(); 199 } 200 201 bool isInvalidated(const AnalysisManager::PreservedAnalyses &pa) { 202 return !pa.isPreserved<AnalysisWithNestedDependency>() || 203 !pa.isPreserved<AnalysisWithDependency>(); 204 } 205 }; 206 207 TEST(AnalysisManagerTest, NestedDependentAnalysis) { 208 MLIRContext context; 209 210 // Create a module. 211 OwningOpRef<ModuleOp> module(ModuleOp::create(UnknownLoc::get(&context))); 212 ModuleAnalysisManager mam(*module, /*passInstrumentor=*/nullptr); 213 AnalysisManager am = mam; 214 215 am.getAnalysis<AnalysisWithNestedDependency>(); 216 EXPECT_TRUE(am.getCachedAnalysis<AnalysisWithNestedDependency>().hasValue()); 217 EXPECT_TRUE(am.getCachedAnalysis<AnalysisWithDependency>().hasValue()); 218 EXPECT_TRUE(am.getCachedAnalysis<MyAnalysis>().hasValue()); 219 220 detail::PreservedAnalyses pa; 221 pa.preserve<AnalysisWithDependency>(); 222 pa.preserve<AnalysisWithNestedDependency>(); 223 am.invalidate(pa); 224 225 EXPECT_FALSE(am.getCachedAnalysis<AnalysisWithNestedDependency>().hasValue()); 226 EXPECT_FALSE(am.getCachedAnalysis<AnalysisWithDependency>().hasValue()); 227 EXPECT_FALSE(am.getCachedAnalysis<MyAnalysis>().hasValue()); 228 } 229 230 struct AnalysisWith2Ctors { 231 AnalysisWith2Ctors(Operation *) { ctor1called = true; } 232 233 AnalysisWith2Ctors(Operation *, AnalysisManager &) { ctor2called = true; } 234 235 bool ctor1called = false; 236 bool ctor2called = false; 237 }; 238 239 TEST(AnalysisManagerTest, DependentAnalysis2Ctors) { 240 MLIRContext context; 241 242 // Create a module. 243 OwningOpRef<ModuleOp> module(ModuleOp::create(UnknownLoc::get(&context))); 244 ModuleAnalysisManager mam(*module, /*passInstrumentor=*/nullptr); 245 AnalysisManager am = mam; 246 247 auto &an = am.getAnalysis<AnalysisWith2Ctors>(); 248 EXPECT_FALSE(an.ctor1called); 249 EXPECT_TRUE(an.ctor2called); 250 } 251 252 } // namespace 253