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