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