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>().hasValue()); 56 EXPECT_FALSE(am.getCachedAnalysis<OtherAnalysis>().hasValue()); 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>().hasValue()); 87 EXPECT_FALSE(fam.getCachedAnalysis<OtherAnalysis>().hasValue()); 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).hasValue()); 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).hasValue()); 121 EXPECT_FALSE(am.getCachedChildAnalysis<OtherAnalysis>(func1).hasValue()); 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>().hasValue()); 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>().hasValue()); 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>().hasValue()); 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>().hasValue()); 198 EXPECT_TRUE(am.getCachedAnalysis<MyAnalysis>().hasValue()); 199 200 detail::PreservedAnalyses pa; 201 pa.preserve<AnalysisWithDependency>(); 202 am.invalidate(pa); 203 204 EXPECT_FALSE(am.getCachedAnalysis<AnalysisWithDependency>().hasValue()); 205 EXPECT_FALSE(am.getCachedAnalysis<MyAnalysis>().hasValue()); 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>().hasValue()); 231 EXPECT_TRUE(am.getCachedAnalysis<AnalysisWithDependency>().hasValue()); 232 EXPECT_TRUE(am.getCachedAnalysis<MyAnalysis>().hasValue()); 233 234 detail::PreservedAnalyses pa; 235 pa.preserve<AnalysisWithDependency>(); 236 pa.preserve<AnalysisWithNestedDependency>(); 237 am.invalidate(pa); 238 239 EXPECT_FALSE(am.getCachedAnalysis<AnalysisWithNestedDependency>().hasValue()); 240 EXPECT_FALSE(am.getCachedAnalysis<AnalysisWithDependency>().hasValue()); 241 EXPECT_FALSE(am.getCachedAnalysis<MyAnalysis>().hasValue()); 242 } 243 244 struct AnalysisWith2Ctors { 245 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(AnalysisWith2Ctors) 246 247 AnalysisWith2Ctors(Operation *) { ctor1called = true; } 248 249 AnalysisWith2Ctors(Operation *, AnalysisManager &) { ctor2called = true; } 250 251 bool ctor1called = false; 252 bool ctor2called = false; 253 }; 254 255 TEST(AnalysisManagerTest, DependentAnalysis2Ctors) { 256 MLIRContext context; 257 258 // Create a module. 259 OwningOpRef<ModuleOp> module(ModuleOp::create(UnknownLoc::get(&context))); 260 ModuleAnalysisManager mam(*module, /*passInstrumentor=*/nullptr); 261 AnalysisManager am = mam; 262 263 auto &an = am.getAnalysis<AnalysisWith2Ctors>(); 264 EXPECT_FALSE(an.ctor1called); 265 EXPECT_TRUE(an.ctor2called); 266 } 267 268 } // namespace 269