1 //===- unittests/IR/PassBuilderCallbacksTest.cpp - PB Callback 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 "llvm/Testing/Support/Error.h"
10 #include <functional>
11 #include <gmock/gmock.h>
12 #include <gtest/gtest.h>
13 #include <llvm/ADT/Any.h>
14 #include <llvm/Analysis/CGSCCPassManager.h>
15 #include <llvm/Analysis/LoopAnalysisManager.h>
16 #include <llvm/AsmParser/Parser.h>
17 #include <llvm/IR/LLVMContext.h>
18 #include <llvm/IR/PassInstrumentation.h>
19 #include <llvm/IR/PassManager.h>
20 #include <llvm/Passes/PassBuilder.h>
21 #include <llvm/Support/Regex.h>
22 #include <llvm/Support/SourceMgr.h>
23 #include <llvm/Transforms/Scalar/LoopPassManager.h>
24
25 using namespace llvm;
26
27 namespace {
28 using testing::AnyNumber;
29 using testing::AtLeast;
30 using testing::DoDefault;
31 using testing::Not;
32 using testing::Return;
33 using testing::Expectation;
34 using testing::Invoke;
35 using testing::WithArgs;
36 using testing::_;
37
38 /// A CRTP base for analysis mock handles
39 ///
40 /// This class reconciles mocking with the value semantics implementation of the
41 /// AnalysisManager. Analysis mock handles should derive from this class and
42 /// call \c setDefault() in their constroctur for wiring up the defaults defined
43 /// by this base with their mock run() and invalidate() implementations.
44 template <typename DerivedT, typename IRUnitT,
45 typename AnalysisManagerT = AnalysisManager<IRUnitT>,
46 typename... ExtraArgTs>
47 class MockAnalysisHandleBase {
48 public:
49 class Analysis : public AnalysisInfoMixin<Analysis> {
50 friend AnalysisInfoMixin<Analysis>;
51 friend MockAnalysisHandleBase;
52 static AnalysisKey Key;
53
54 DerivedT *Handle;
55
Analysis(DerivedT & Handle)56 Analysis(DerivedT &Handle) : Handle(&Handle) {
57 static_assert(std::is_base_of<MockAnalysisHandleBase, DerivedT>::value,
58 "Must pass the derived type to this template!");
59 }
60
61 public:
62 class Result {
63 friend MockAnalysisHandleBase;
64
65 DerivedT *Handle;
66
Result(DerivedT & Handle)67 Result(DerivedT &Handle) : Handle(&Handle) {}
68
69 public:
70 // Forward invalidation events to the mock handle.
invalidate(IRUnitT & IR,const PreservedAnalyses & PA,typename AnalysisManagerT::Invalidator & Inv)71 bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA,
72 typename AnalysisManagerT::Invalidator &Inv) {
73 return Handle->invalidate(IR, PA, Inv);
74 }
75 };
76
run(IRUnitT & IR,AnalysisManagerT & AM,ExtraArgTs...ExtraArgs)77 Result run(IRUnitT &IR, AnalysisManagerT &AM, ExtraArgTs... ExtraArgs) {
78 return Handle->run(IR, AM, ExtraArgs...);
79 }
80 };
81
getAnalysis()82 Analysis getAnalysis() { return Analysis(static_cast<DerivedT &>(*this)); }
getResult()83 typename Analysis::Result getResult() {
84 return typename Analysis::Result(static_cast<DerivedT &>(*this));
85 }
getName()86 static StringRef getName() { return llvm::getTypeName<DerivedT>(); }
87
88 protected:
89 // FIXME: MSVC seems unable to handle a lambda argument to Invoke from within
90 // the template, so we use a boring static function.
invalidateCallback(IRUnitT & IR,const PreservedAnalyses & PA,typename AnalysisManagerT::Invalidator & Inv)91 static bool invalidateCallback(IRUnitT &IR, const PreservedAnalyses &PA,
92 typename AnalysisManagerT::Invalidator &Inv) {
93 auto PAC = PA.template getChecker<Analysis>();
94 return !PAC.preserved() &&
95 !PAC.template preservedSet<AllAnalysesOn<IRUnitT>>();
96 }
97
98 /// Derived classes should call this in their constructor to set up default
99 /// mock actions. (We can't do this in our constructor because this has to
100 /// run after the DerivedT is constructed.)
setDefaults()101 void setDefaults() {
102 ON_CALL(static_cast<DerivedT &>(*this),
103 run(_, _, testing::Matcher<ExtraArgTs>(_)...))
104 .WillByDefault(Return(this->getResult()));
105 ON_CALL(static_cast<DerivedT &>(*this), invalidate(_, _, _))
106 .WillByDefault(Invoke(&invalidateCallback));
107 }
108 };
109
110 /// A CRTP base for pass mock handles
111 ///
112 /// This class reconciles mocking with the value semantics implementation of the
113 /// PassManager. Pass mock handles should derive from this class and
114 /// call \c setDefault() in their constroctur for wiring up the defaults defined
115 /// by this base with their mock run() and invalidate() implementations.
116 template <typename DerivedT, typename IRUnitT, typename AnalysisManagerT,
117 typename... ExtraArgTs>
118 AnalysisKey MockAnalysisHandleBase<DerivedT, IRUnitT, AnalysisManagerT,
119 ExtraArgTs...>::Analysis::Key;
120
121 template <typename DerivedT, typename IRUnitT,
122 typename AnalysisManagerT = AnalysisManager<IRUnitT>,
123 typename... ExtraArgTs>
124 class MockPassHandleBase {
125 public:
126 class Pass : public PassInfoMixin<Pass> {
127 friend MockPassHandleBase;
128
129 DerivedT *Handle;
130
Pass(DerivedT & Handle)131 Pass(DerivedT &Handle) : Handle(&Handle) {
132 static_assert(std::is_base_of<MockPassHandleBase, DerivedT>::value,
133 "Must pass the derived type to this template!");
134 }
135
136 public:
run(IRUnitT & IR,AnalysisManagerT & AM,ExtraArgTs...ExtraArgs)137 PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM,
138 ExtraArgTs... ExtraArgs) {
139 return Handle->run(IR, AM, ExtraArgs...);
140 }
141 };
142
getName()143 static StringRef getName() { return llvm::getTypeName<DerivedT>(); }
144
getPass()145 Pass getPass() { return Pass(static_cast<DerivedT &>(*this)); }
146
147 protected:
148 /// Derived classes should call this in their constructor to set up default
149 /// mock actions. (We can't do this in our constructor because this has to
150 /// run after the DerivedT is constructed.)
setDefaults()151 void setDefaults() {
152 ON_CALL(static_cast<DerivedT &>(*this),
153 run(_, _, testing::Matcher<ExtraArgTs>(_)...))
154 .WillByDefault(Return(PreservedAnalyses::all()));
155 }
156 };
157
158 /// Mock handles for passes for the IRUnits Module, CGSCC, Function, Loop.
159 /// These handles define the appropriate run() mock interface for the respective
160 /// IRUnit type.
161 template <typename IRUnitT> struct MockPassHandle;
162 template <>
163 struct MockPassHandle<Loop>
164 : MockPassHandleBase<MockPassHandle<Loop>, Loop, LoopAnalysisManager,
165 LoopStandardAnalysisResults &, LPMUpdater &> {
166 MOCK_METHOD4(run,
167 PreservedAnalyses(Loop &, LoopAnalysisManager &,
168 LoopStandardAnalysisResults &, LPMUpdater &));
invalidateLoop__anona00a216b0111::MockPassHandle169 static void invalidateLoop(Loop &L, LoopAnalysisManager &,
170 LoopStandardAnalysisResults &,
171 LPMUpdater &Updater) {
172 Updater.markLoopAsDeleted(L, L.getName());
173 }
MockPassHandle__anona00a216b0111::MockPassHandle174 MockPassHandle() { setDefaults(); }
175 };
176
177 template <>
178 struct MockPassHandle<Function>
179 : MockPassHandleBase<MockPassHandle<Function>, Function> {
180 MOCK_METHOD2(run, PreservedAnalyses(Function &, FunctionAnalysisManager &));
181
MockPassHandle__anona00a216b0111::MockPassHandle182 MockPassHandle() { setDefaults(); }
183 };
184
185 template <>
186 struct MockPassHandle<LazyCallGraph::SCC>
187 : MockPassHandleBase<MockPassHandle<LazyCallGraph::SCC>, LazyCallGraph::SCC,
188 CGSCCAnalysisManager, LazyCallGraph &,
189 CGSCCUpdateResult &> {
190 MOCK_METHOD4(run,
191 PreservedAnalyses(LazyCallGraph::SCC &, CGSCCAnalysisManager &,
192 LazyCallGraph &G, CGSCCUpdateResult &UR));
193
invalidateSCC__anona00a216b0111::MockPassHandle194 static void invalidateSCC(LazyCallGraph::SCC &C, CGSCCAnalysisManager &,
195 LazyCallGraph &, CGSCCUpdateResult &UR) {
196 UR.InvalidatedSCCs.insert(&C);
197 }
198
MockPassHandle__anona00a216b0111::MockPassHandle199 MockPassHandle() { setDefaults(); }
200 };
201
202 template <>
203 struct MockPassHandle<Module>
204 : MockPassHandleBase<MockPassHandle<Module>, Module> {
205 MOCK_METHOD2(run, PreservedAnalyses(Module &, ModuleAnalysisManager &));
206
MockPassHandle__anona00a216b0111::MockPassHandle207 MockPassHandle() { setDefaults(); }
208 };
209
210 /// Mock handles for analyses for the IRUnits Module, CGSCC, Function, Loop.
211 /// These handles define the appropriate run() and invalidate() mock interfaces
212 /// for the respective IRUnit type.
213 template <typename IRUnitT> struct MockAnalysisHandle;
214 template <>
215 struct MockAnalysisHandle<Loop>
216 : MockAnalysisHandleBase<MockAnalysisHandle<Loop>, Loop,
217 LoopAnalysisManager,
218 LoopStandardAnalysisResults &> {
219
220 MOCK_METHOD3_T(run, typename Analysis::Result(Loop &, LoopAnalysisManager &,
221 LoopStandardAnalysisResults &));
222
223 MOCK_METHOD3_T(invalidate, bool(Loop &, const PreservedAnalyses &,
224 LoopAnalysisManager::Invalidator &));
225
MockAnalysisHandle__anona00a216b0111::MockAnalysisHandle226 MockAnalysisHandle<Loop>() { this->setDefaults(); }
227 };
228
229 template <>
230 struct MockAnalysisHandle<Function>
231 : MockAnalysisHandleBase<MockAnalysisHandle<Function>, Function> {
232 MOCK_METHOD2(run, Analysis::Result(Function &, FunctionAnalysisManager &));
233
234 MOCK_METHOD3(invalidate, bool(Function &, const PreservedAnalyses &,
235 FunctionAnalysisManager::Invalidator &));
236
MockAnalysisHandle__anona00a216b0111::MockAnalysisHandle237 MockAnalysisHandle<Function>() { setDefaults(); }
238 };
239
240 template <>
241 struct MockAnalysisHandle<LazyCallGraph::SCC>
242 : MockAnalysisHandleBase<MockAnalysisHandle<LazyCallGraph::SCC>,
243 LazyCallGraph::SCC, CGSCCAnalysisManager,
244 LazyCallGraph &> {
245 MOCK_METHOD3(run, Analysis::Result(LazyCallGraph::SCC &,
246 CGSCCAnalysisManager &, LazyCallGraph &));
247
248 MOCK_METHOD3(invalidate, bool(LazyCallGraph::SCC &, const PreservedAnalyses &,
249 CGSCCAnalysisManager::Invalidator &));
250
MockAnalysisHandle__anona00a216b0111::MockAnalysisHandle251 MockAnalysisHandle<LazyCallGraph::SCC>() { setDefaults(); }
252 };
253
254 template <>
255 struct MockAnalysisHandle<Module>
256 : MockAnalysisHandleBase<MockAnalysisHandle<Module>, Module> {
257 MOCK_METHOD2(run, Analysis::Result(Module &, ModuleAnalysisManager &));
258
259 MOCK_METHOD3(invalidate, bool(Module &, const PreservedAnalyses &,
260 ModuleAnalysisManager::Invalidator &));
261
MockAnalysisHandle__anona00a216b0111::MockAnalysisHandle262 MockAnalysisHandle<Module>() { setDefaults(); }
263 };
264
parseIR(LLVMContext & C,const char * IR)265 static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
266 SMDiagnostic Err;
267 return parseAssemblyString(IR, Err, C);
268 }
269
270 /// Helper for HasName matcher that returns getName both for IRUnit and
271 /// for IRUnit pointer wrapper into llvm::Any (wrapped by PassInstrumentation).
getName(const IRUnitT & IR)272 template <typename IRUnitT> std::string getName(const IRUnitT &IR) {
273 return std::string(IR.getName());
274 }
275
getName(const StringRef & name)276 template <> std::string getName(const StringRef &name) {
277 return std::string(name);
278 }
279
getName(const llvm::Any & WrappedIR)280 template <> std::string getName(const llvm::Any &WrappedIR) {
281 if (any_isa<const Module *>(WrappedIR))
282 return any_cast<const Module *>(WrappedIR)->getName().str();
283 if (any_isa<const Function *>(WrappedIR))
284 return any_cast<const Function *>(WrappedIR)->getName().str();
285 if (any_isa<const Loop *>(WrappedIR))
286 return any_cast<const Loop *>(WrappedIR)->getName().str();
287 if (any_isa<const LazyCallGraph::SCC *>(WrappedIR))
288 return any_cast<const LazyCallGraph::SCC *>(WrappedIR)->getName();
289 return "<UNKNOWN>";
290 }
291 /// Define a custom matcher for objects which support a 'getName' method.
292 ///
293 /// LLVM often has IR objects or analysis objects which expose a name
294 /// and in tests it is convenient to match these by name for readability.
295 /// Usually, this name is either a StringRef or a plain std::string. This
296 /// matcher supports any type exposing a getName() method of this form whose
297 /// return value is compatible with an std::ostream. For StringRef, this uses
298 /// the shift operator defined above.
299 ///
300 /// It should be used as:
301 ///
302 /// HasName("my_function")
303 ///
304 /// No namespace or other qualification is required.
305 MATCHER_P(HasName, Name, "") {
306 *result_listener << "has name '" << getName(arg) << "'";
307 return Name == getName(arg);
308 }
309
310 MATCHER_P(HasNameRegex, Name, "") {
311 *result_listener << "has name '" << getName(arg) << "'";
312 llvm::Regex r(Name);
313 return r.match(getName(arg));
314 }
315
316 struct MockPassInstrumentationCallbacks {
317 PassInstrumentationCallbacks Callbacks;
318
MockPassInstrumentationCallbacks__anona00a216b0111::MockPassInstrumentationCallbacks319 MockPassInstrumentationCallbacks() {
320 ON_CALL(*this, runBeforePass(_, _)).WillByDefault(Return(true));
321 }
322 MOCK_METHOD2(runBeforePass, bool(StringRef PassID, llvm::Any));
323 MOCK_METHOD2(runBeforeSkippedPass, void(StringRef PassID, llvm::Any));
324 MOCK_METHOD2(runBeforeNonSkippedPass, void(StringRef PassID, llvm::Any));
325 MOCK_METHOD3(runAfterPass,
326 void(StringRef PassID, llvm::Any, const PreservedAnalyses &PA));
327 MOCK_METHOD2(runAfterPassInvalidated,
328 void(StringRef PassID, const PreservedAnalyses &PA));
329 MOCK_METHOD2(runBeforeAnalysis, void(StringRef PassID, llvm::Any));
330 MOCK_METHOD2(runAfterAnalysis, void(StringRef PassID, llvm::Any));
331
registerPassInstrumentation__anona00a216b0111::MockPassInstrumentationCallbacks332 void registerPassInstrumentation() {
333 Callbacks.registerShouldRunOptionalPassCallback(
334 [this](StringRef P, llvm::Any IR) {
335 return this->runBeforePass(P, IR);
336 });
337 Callbacks.registerBeforeSkippedPassCallback(
338 [this](StringRef P, llvm::Any IR) {
339 this->runBeforeSkippedPass(P, IR);
340 });
341 Callbacks.registerBeforeNonSkippedPassCallback(
342 [this](StringRef P, llvm::Any IR) {
343 this->runBeforeNonSkippedPass(P, IR);
344 });
345 Callbacks.registerAfterPassCallback(
346 [this](StringRef P, llvm::Any IR, const PreservedAnalyses &PA) {
347 this->runAfterPass(P, IR, PA);
348 });
349 Callbacks.registerAfterPassInvalidatedCallback(
350 [this](StringRef P, const PreservedAnalyses &PA) {
351 this->runAfterPassInvalidated(P, PA);
352 });
353 Callbacks.registerBeforeAnalysisCallback([this](StringRef P, llvm::Any IR) {
354 return this->runBeforeAnalysis(P, IR);
355 });
356 Callbacks.registerAfterAnalysisCallback(
357 [this](StringRef P, llvm::Any IR) { this->runAfterAnalysis(P, IR); });
358 }
359
ignoreNonMockPassInstrumentation__anona00a216b0111::MockPassInstrumentationCallbacks360 void ignoreNonMockPassInstrumentation(StringRef IRName) {
361 // Generic EXPECT_CALLs are needed to match instrumentation on unimportant
362 // parts of a pipeline that we do not care about (e.g. various passes added
363 // by default by PassBuilder - Verifier pass etc).
364 // Make sure to avoid ignoring Mock passes/analysis, we definitely want
365 // to check these explicitly.
366 EXPECT_CALL(*this,
367 runBeforePass(Not(HasNameRegex("Mock")), HasName(IRName)))
368 .Times(AnyNumber());
369 EXPECT_CALL(
370 *this, runBeforeSkippedPass(Not(HasNameRegex("Mock")), HasName(IRName)))
371 .Times(AnyNumber());
372 EXPECT_CALL(*this, runBeforeNonSkippedPass(Not(HasNameRegex("Mock")),
373 HasName(IRName)))
374 .Times(AnyNumber());
375 EXPECT_CALL(*this,
376 runAfterPass(Not(HasNameRegex("Mock")), HasName(IRName), _))
377 .Times(AnyNumber());
378 EXPECT_CALL(*this,
379 runBeforeAnalysis(Not(HasNameRegex("Mock")), HasName(IRName)))
380 .Times(AnyNumber());
381 EXPECT_CALL(*this,
382 runAfterAnalysis(Not(HasNameRegex("Mock")), HasName(IRName)))
383 .Times(AnyNumber());
384 }
385 };
386
387 template <typename PassManagerT> class PassBuilderCallbacksTest;
388
389 /// This test fixture is shared between all the actual tests below and
390 /// takes care of setting up appropriate defaults.
391 ///
392 /// The template specialization serves to extract the IRUnit and AM types from
393 /// the given PassManagerT.
394 template <typename TestIRUnitT, typename... ExtraPassArgTs,
395 typename... ExtraAnalysisArgTs>
396 class PassBuilderCallbacksTest<PassManager<
397 TestIRUnitT, AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>,
398 ExtraPassArgTs...>> : public testing::Test {
399 protected:
400 using IRUnitT = TestIRUnitT;
401 using AnalysisManagerT = AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>;
402 using PassManagerT =
403 PassManager<TestIRUnitT, AnalysisManagerT, ExtraPassArgTs...>;
404 using AnalysisT = typename MockAnalysisHandle<IRUnitT>::Analysis;
405
406 LLVMContext Context;
407 std::unique_ptr<Module> M;
408
409 MockPassInstrumentationCallbacks CallbacksHandle;
410
411 PassBuilder PB;
412 ModulePassManager PM;
413 LoopAnalysisManager LAM;
414 FunctionAnalysisManager FAM;
415 CGSCCAnalysisManager CGAM;
416 ModuleAnalysisManager AM;
417
418 MockPassHandle<IRUnitT> PassHandle;
419 MockAnalysisHandle<IRUnitT> AnalysisHandle;
420
getAnalysisResult(IRUnitT & U,AnalysisManagerT & AM,ExtraAnalysisArgTs &&...Args)421 static PreservedAnalyses getAnalysisResult(IRUnitT &U, AnalysisManagerT &AM,
422 ExtraAnalysisArgTs &&... Args) {
423 (void)AM.template getResult<AnalysisT>(
424 U, std::forward<ExtraAnalysisArgTs>(Args)...);
425 return PreservedAnalyses::all();
426 }
427
PassBuilderCallbacksTest()428 PassBuilderCallbacksTest()
429 : M(parseIR(Context,
430 "declare void @bar()\n"
431 "define void @foo(i32 %n) {\n"
432 "entry:\n"
433 " br label %loop\n"
434 "loop:\n"
435 " %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]\n"
436 " %iv.next = add i32 %iv, 1\n"
437 " tail call void @bar()\n"
438 " %cmp = icmp eq i32 %iv, %n\n"
439 " br i1 %cmp, label %exit, label %loop\n"
440 "exit:\n"
441 " ret void\n"
442 "}\n")),
443 CallbacksHandle(), PB(false, nullptr, PipelineTuningOptions(), None,
444 &CallbacksHandle.Callbacks),
445 PM(true), LAM(true), FAM(true), CGAM(true), AM(true) {
446
447 EXPECT_TRUE(&CallbacksHandle.Callbacks ==
448 PB.getPassInstrumentationCallbacks());
449
450 /// Register a callback for analysis registration.
451 ///
452 /// The callback is a function taking a reference to an AnalyisManager
453 /// object. When called, the callee gets to register its own analyses with
454 /// this PassBuilder instance.
455 PB.registerAnalysisRegistrationCallback([this](AnalysisManagerT &AM) {
456 // Register our mock analysis
457 AM.registerPass([this] { return AnalysisHandle.getAnalysis(); });
458 });
459
460 /// Register a callback for pipeline parsing.
461 ///
462 /// During parsing of a textual pipeline, the PassBuilder will call these
463 /// callbacks for each encountered pass name that it does not know. This
464 /// includes both simple pass names as well as names of sub-pipelines. In
465 /// the latter case, the InnerPipeline is not empty.
466 PB.registerPipelineParsingCallback(
467 [this](StringRef Name, PassManagerT &PM,
468 ArrayRef<PassBuilder::PipelineElement> InnerPipeline) {
469 /// Handle parsing of the names of analysis utilities such as
470 /// require<test-analysis> and invalidate<test-analysis> for our
471 /// analysis mock handle
472 if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis", Name, PM))
473 return true;
474
475 /// Parse the name of our pass mock handle
476 if (Name == "test-transform") {
477 PM.addPass(PassHandle.getPass());
478 return true;
479 }
480 return false;
481 });
482
483 /// Register builtin analyses and cross-register the analysis proxies
484 PB.registerModuleAnalyses(AM);
485 PB.registerCGSCCAnalyses(CGAM);
486 PB.registerFunctionAnalyses(FAM);
487 PB.registerLoopAnalyses(LAM);
488 PB.crossRegisterProxies(LAM, FAM, CGAM, AM);
489 }
490 };
491
492 using ModuleCallbacksTest = PassBuilderCallbacksTest<ModulePassManager>;
493 using CGSCCCallbacksTest = PassBuilderCallbacksTest<CGSCCPassManager>;
494 using FunctionCallbacksTest = PassBuilderCallbacksTest<FunctionPassManager>;
495 using LoopCallbacksTest = PassBuilderCallbacksTest<LoopPassManager>;
496
497 /// Test parsing of the name of our mock pass for all IRUnits.
498 ///
499 /// The pass should by default run our mock analysis and then preserve it.
TEST_F(ModuleCallbacksTest,Passes)500 TEST_F(ModuleCallbacksTest, Passes) {
501 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
502 EXPECT_CALL(PassHandle, run(HasName("<string>"), _))
503 .WillOnce(Invoke(getAnalysisResult));
504
505 StringRef PipelineText = "test-transform";
506 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
507 << "Pipeline was: " << PipelineText;
508
509 PM.run(*M, AM);
510 }
511
TEST_F(ModuleCallbacksTest,InstrumentedPasses)512 TEST_F(ModuleCallbacksTest, InstrumentedPasses) {
513 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
514 EXPECT_CALL(PassHandle, run(HasName("<string>"), _))
515 .WillOnce(Invoke(getAnalysisResult));
516
517 CallbacksHandle.registerPassInstrumentation();
518 // Non-mock instrumentation not specifically mentioned below can be ignored.
519 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
520
521 // PassInstrumentation calls should happen in-sequence, in the same order
522 // as passes/analyses are scheduled.
523 ::testing::Sequence PISequence;
524 EXPECT_CALL(CallbacksHandle, runBeforePass(HasNameRegex("MockPassHandle"),
525 HasName("<string>")))
526 .InSequence(PISequence);
527 EXPECT_CALL(CallbacksHandle,
528 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"),
529 HasName("<string>")))
530 .InSequence(PISequence);
531 EXPECT_CALL(CallbacksHandle,
532 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"),
533 HasName("<string>")))
534 .InSequence(PISequence);
535 EXPECT_CALL(
536 CallbacksHandle,
537 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("<string>")))
538 .InSequence(PISequence);
539 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"),
540 HasName("<string>"), _))
541 .InSequence(PISequence);
542
543 // No passes are skipped, so there should be no calls to
544 // runBeforeSkippedPass().
545 EXPECT_CALL(
546 CallbacksHandle,
547 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("<string>")))
548 .Times(0);
549
550 StringRef PipelineText = "test-transform";
551 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
552 << "Pipeline was: " << PipelineText;
553
554 PM.run(*M, AM);
555 }
556
TEST_F(ModuleCallbacksTest,InstrumentedSkippedPasses)557 TEST_F(ModuleCallbacksTest, InstrumentedSkippedPasses) {
558 CallbacksHandle.registerPassInstrumentation();
559 // Non-mock instrumentation run here can safely be ignored.
560 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
561 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
562
563 // Skip all passes by returning false. Pass managers and adaptor passes are
564 // also passes that observed by the callbacks.
565 EXPECT_CALL(CallbacksHandle, runBeforePass(_, _))
566 .WillRepeatedly(Return(false));
567
568 EXPECT_CALL(CallbacksHandle,
569 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), _))
570 .Times(3);
571
572 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)).Times(0);
573 EXPECT_CALL(PassHandle, run(HasName("<string>"), _)).Times(0);
574
575 // As the pass is skipped there is no nonskippedpass/afterPass,
576 // beforeAnalysis/afterAnalysis as well.
577 EXPECT_CALL(CallbacksHandle,
578 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), _))
579 .Times(0);
580 EXPECT_CALL(CallbacksHandle,
581 runAfterPass(HasNameRegex("MockPassHandle"), _, _))
582 .Times(0);
583 EXPECT_CALL(CallbacksHandle,
584 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))
585 .Times(0);
586 EXPECT_CALL(CallbacksHandle,
587 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))
588 .Times(0);
589
590 // Order is important here. `Adaptor` expectations should be checked first
591 // because the its argument contains 'PassManager' (for example:
592 // ModuleToFunctionPassAdaptor{{.*}}PassManager{{.*}}). Check
593 // `runBeforeNonSkippedPass` and `runAfterPass` to show that they are not
594 // skipped.
595 //
596 // Pass managers are not ignored.
597 // 5 = (1) ModulePassManager + (2) FunctionPassMangers + (1) LoopPassManager +
598 // (1) CGSCCPassManager
599 EXPECT_CALL(CallbacksHandle,
600 runBeforeNonSkippedPass(HasNameRegex("PassManager"), _))
601 .Times(5);
602 EXPECT_CALL(
603 CallbacksHandle,
604 runBeforeNonSkippedPass(HasNameRegex("ModuleToFunctionPassAdaptor"), _))
605 .Times(1);
606 EXPECT_CALL(CallbacksHandle,
607 runBeforeNonSkippedPass(
608 HasNameRegex("ModuleToPostOrderCGSCCPassAdaptor"), _))
609 .Times(1);
610 EXPECT_CALL(
611 CallbacksHandle,
612 runBeforeNonSkippedPass(HasNameRegex("CGSCCToFunctionPassAdaptor"), _))
613 .Times(1);
614 EXPECT_CALL(
615 CallbacksHandle,
616 runBeforeNonSkippedPass(HasNameRegex("FunctionToLoopPassAdaptor"), _))
617 .Times(1);
618
619 // The `runAfterPass` checks are the same as these of
620 // `runBeforeNonSkippedPass`.
621 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("PassManager"), _, _))
622 .Times(5);
623 EXPECT_CALL(CallbacksHandle,
624 runAfterPass(HasNameRegex("ModuleToFunctionPassAdaptor"), _, _))
625 .Times(1);
626 EXPECT_CALL(
627 CallbacksHandle,
628 runAfterPass(HasNameRegex("ModuleToPostOrderCGSCCPassAdaptor"), _, _))
629 .Times(1);
630 EXPECT_CALL(CallbacksHandle,
631 runAfterPass(HasNameRegex("CGSCCToFunctionPassAdaptor"), _, _))
632 .Times(1);
633 EXPECT_CALL(CallbacksHandle,
634 runAfterPass(HasNameRegex("FunctionToLoopPassAdaptor"), _, _))
635 .Times(1);
636
637 // Ignore analyses introduced by adaptor passes.
638 EXPECT_CALL(CallbacksHandle,
639 runBeforeAnalysis(Not(HasNameRegex("MockAnalysisHandle")), _))
640 .Times(AnyNumber());
641 EXPECT_CALL(CallbacksHandle,
642 runAfterAnalysis(Not(HasNameRegex("MockAnalysisHandle")), _))
643 .Times(AnyNumber());
644
645 // Register Funtion and Loop version of "test-transform" for testing
646 PB.registerPipelineParsingCallback(
647 [](StringRef Name, FunctionPassManager &FPM,
648 ArrayRef<PassBuilder::PipelineElement>) {
649 if (Name == "test-transform") {
650 FPM.addPass(MockPassHandle<Function>().getPass());
651 return true;
652 }
653 return false;
654 });
655 PB.registerPipelineParsingCallback(
656 [](StringRef Name, LoopPassManager &LPM,
657 ArrayRef<PassBuilder::PipelineElement>) {
658 if (Name == "test-transform") {
659 LPM.addPass(MockPassHandle<Loop>().getPass());
660 return true;
661 }
662 return false;
663 });
664
665 StringRef PipelineText = "test-transform,function(test-transform),cgscc("
666 "function(loop(test-transform)))";
667 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
668 << "Pipeline was: " << PipelineText;
669
670 PM.run(*M, AM);
671 }
672
TEST_F(FunctionCallbacksTest,Passes)673 TEST_F(FunctionCallbacksTest, Passes) {
674 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));
675 EXPECT_CALL(PassHandle, run(HasName("foo"), _))
676 .WillOnce(Invoke(getAnalysisResult));
677
678 StringRef PipelineText = "test-transform";
679 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
680 << "Pipeline was: " << PipelineText;
681 PM.run(*M, AM);
682 }
683
TEST_F(FunctionCallbacksTest,InstrumentedPasses)684 TEST_F(FunctionCallbacksTest, InstrumentedPasses) {
685 CallbacksHandle.registerPassInstrumentation();
686 // Non-mock instrumentation not specifically mentioned below can be ignored.
687 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
688 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
689
690 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));
691 EXPECT_CALL(PassHandle, run(HasName("foo"), _))
692 .WillOnce(Invoke(getAnalysisResult));
693
694 // PassInstrumentation calls should happen in-sequence, in the same order
695 // as passes/analyses are scheduled.
696 ::testing::Sequence PISequence;
697 EXPECT_CALL(CallbacksHandle,
698 runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo")))
699 .InSequence(PISequence);
700 EXPECT_CALL(
701 CallbacksHandle,
702 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("foo")))
703 .InSequence(PISequence);
704 EXPECT_CALL(
705 CallbacksHandle,
706 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo")))
707 .InSequence(PISequence);
708 EXPECT_CALL(
709 CallbacksHandle,
710 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo")))
711 .InSequence(PISequence);
712 EXPECT_CALL(CallbacksHandle,
713 runAfterPass(HasNameRegex("MockPassHandle"), HasName("foo"), _))
714 .InSequence(PISequence);
715
716 // No passes are skipped, so there should be no calls to
717 // runBeforeSkippedPass().
718 EXPECT_CALL(
719 CallbacksHandle,
720 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("foo")))
721 .Times(0);
722
723 // Our mock pass does not invalidate IR.
724 EXPECT_CALL(CallbacksHandle,
725 runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))
726 .Times(0);
727
728 StringRef PipelineText = "test-transform";
729 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
730 << "Pipeline was: " << PipelineText;
731 PM.run(*M, AM);
732 }
733
TEST_F(FunctionCallbacksTest,InstrumentedSkippedPasses)734 TEST_F(FunctionCallbacksTest, InstrumentedSkippedPasses) {
735 CallbacksHandle.registerPassInstrumentation();
736 // Non-mock instrumentation run here can safely be ignored.
737 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
738 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
739
740 // Skip the pass by returning false.
741 EXPECT_CALL(CallbacksHandle,
742 runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo")))
743 .WillOnce(Return(false));
744
745 EXPECT_CALL(
746 CallbacksHandle,
747 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("foo")))
748 .Times(1);
749
750 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _)).Times(0);
751 EXPECT_CALL(PassHandle, run(HasName("foo"), _)).Times(0);
752
753 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis
754 // as well.
755 EXPECT_CALL(CallbacksHandle,
756 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), _))
757 .Times(0);
758 EXPECT_CALL(CallbacksHandle,
759 runAfterPass(HasNameRegex("MockPassHandle"), _, _))
760 .Times(0);
761 EXPECT_CALL(CallbacksHandle,
762 runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))
763 .Times(0);
764 EXPECT_CALL(CallbacksHandle,
765 runAfterPass(HasNameRegex("MockPassHandle"), _, _))
766 .Times(0);
767 EXPECT_CALL(CallbacksHandle,
768 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))
769 .Times(0);
770 EXPECT_CALL(CallbacksHandle,
771 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))
772 .Times(0);
773
774 StringRef PipelineText = "test-transform";
775 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
776 << "Pipeline was: " << PipelineText;
777 PM.run(*M, AM);
778 }
779
TEST_F(LoopCallbacksTest,Passes)780 TEST_F(LoopCallbacksTest, Passes) {
781 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
782 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))
783 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
784
785 StringRef PipelineText = "test-transform";
786 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
787 << "Pipeline was: " << PipelineText;
788 PM.run(*M, AM);
789 }
790
TEST_F(LoopCallbacksTest,InstrumentedPasses)791 TEST_F(LoopCallbacksTest, InstrumentedPasses) {
792 CallbacksHandle.registerPassInstrumentation();
793 // Non-mock instrumentation not specifically mentioned below can be ignored.
794 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
795 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
796 CallbacksHandle.ignoreNonMockPassInstrumentation("loop");
797
798 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
799 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))
800 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
801
802 // PassInstrumentation calls should happen in-sequence, in the same order
803 // as passes/analyses are scheduled.
804 ::testing::Sequence PISequence;
805 EXPECT_CALL(CallbacksHandle,
806 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
807 .InSequence(PISequence);
808 EXPECT_CALL(
809 CallbacksHandle,
810 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("loop")))
811 .InSequence(PISequence);
812 EXPECT_CALL(
813 CallbacksHandle,
814 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
815 .InSequence(PISequence);
816 EXPECT_CALL(
817 CallbacksHandle,
818 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
819 .InSequence(PISequence);
820 EXPECT_CALL(CallbacksHandle,
821 runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop"), _))
822 .InSequence(PISequence);
823
824 // Our mock pass does not invalidate IR.
825 EXPECT_CALL(CallbacksHandle,
826 runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))
827 .Times(0);
828
829 // No passes are skipped, so there should be no calls to
830 // runBeforeSkippedPass().
831 EXPECT_CALL(
832 CallbacksHandle,
833 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("loop")))
834 .Times(0);
835
836 StringRef PipelineText = "test-transform";
837 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
838 << "Pipeline was: " << PipelineText;
839 PM.run(*M, AM);
840 }
841
TEST_F(LoopCallbacksTest,InstrumentedInvalidatingPasses)842 TEST_F(LoopCallbacksTest, InstrumentedInvalidatingPasses) {
843 CallbacksHandle.registerPassInstrumentation();
844 // Non-mock instrumentation not specifically mentioned below can be ignored.
845 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
846 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
847 CallbacksHandle.ignoreNonMockPassInstrumentation("loop");
848
849 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
850 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))
851 .WillOnce(DoAll(WithArgs<0, 1, 2, 3>(Invoke(PassHandle.invalidateLoop)),
852 WithArgs<0, 1, 2>(Invoke(getAnalysisResult))));
853
854 // PassInstrumentation calls should happen in-sequence, in the same order
855 // as passes/analyses are scheduled.
856 ::testing::Sequence PISequence;
857 EXPECT_CALL(CallbacksHandle,
858 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
859 .InSequence(PISequence);
860 EXPECT_CALL(
861 CallbacksHandle,
862 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("loop")))
863 .InSequence(PISequence);
864 EXPECT_CALL(
865 CallbacksHandle,
866 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
867 .InSequence(PISequence);
868 EXPECT_CALL(
869 CallbacksHandle,
870 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
871 .InSequence(PISequence);
872 EXPECT_CALL(CallbacksHandle,
873 runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))
874 .InSequence(PISequence);
875 EXPECT_CALL(CallbacksHandle,
876 runAfterPassInvalidated(HasNameRegex("^PassManager"), _))
877 .InSequence(PISequence);
878
879 // Our mock pass invalidates IR, thus normal runAfterPass is never called.
880 EXPECT_CALL(CallbacksHandle,
881 runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop"), _))
882 .Times(0);
883
884 StringRef PipelineText = "test-transform";
885 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
886 << "Pipeline was: " << PipelineText;
887 PM.run(*M, AM);
888 }
889
TEST_F(LoopCallbacksTest,InstrumentedSkippedPasses)890 TEST_F(LoopCallbacksTest, InstrumentedSkippedPasses) {
891 CallbacksHandle.registerPassInstrumentation();
892 // Non-mock instrumentation run here can safely be ignored.
893 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
894 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
895 CallbacksHandle.ignoreNonMockPassInstrumentation("loop");
896
897 // Skip the pass by returning false.
898 EXPECT_CALL(CallbacksHandle,
899 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
900 .WillOnce(Return(false));
901
902 EXPECT_CALL(
903 CallbacksHandle,
904 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("loop")))
905 .Times(1);
906
907 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)).Times(0);
908 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _)).Times(0);
909
910 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis
911 // as well.
912 EXPECT_CALL(CallbacksHandle,
913 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), _))
914 .Times(0);
915 EXPECT_CALL(CallbacksHandle,
916 runAfterPass(HasNameRegex("MockPassHandle"), _, _))
917 .Times(0);
918 EXPECT_CALL(CallbacksHandle,
919 runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))
920 .Times(0);
921 EXPECT_CALL(CallbacksHandle,
922 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))
923 .Times(0);
924 EXPECT_CALL(CallbacksHandle,
925 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))
926 .Times(0);
927
928 StringRef PipelineText = "test-transform";
929 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
930 << "Pipeline was: " << PipelineText;
931 PM.run(*M, AM);
932 }
933
TEST_F(CGSCCCallbacksTest,Passes)934 TEST_F(CGSCCCallbacksTest, Passes) {
935 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
936 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _))
937 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
938
939 StringRef PipelineText = "test-transform";
940 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
941 << "Pipeline was: " << PipelineText;
942 PM.run(*M, AM);
943 }
944
TEST_F(CGSCCCallbacksTest,InstrumentedPasses)945 TEST_F(CGSCCCallbacksTest, InstrumentedPasses) {
946 CallbacksHandle.registerPassInstrumentation();
947 // Non-mock instrumentation not specifically mentioned below can be ignored.
948 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
949 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
950 CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)");
951
952 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
953 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _))
954 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
955
956 // PassInstrumentation calls should happen in-sequence, in the same order
957 // as passes/analyses are scheduled.
958 ::testing::Sequence PISequence;
959 EXPECT_CALL(CallbacksHandle,
960 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
961 .InSequence(PISequence);
962 EXPECT_CALL(
963 CallbacksHandle,
964 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
965 .InSequence(PISequence);
966 EXPECT_CALL(
967 CallbacksHandle,
968 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
969 .InSequence(PISequence);
970 EXPECT_CALL(
971 CallbacksHandle,
972 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
973 .InSequence(PISequence);
974 EXPECT_CALL(CallbacksHandle,
975 runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)"), _))
976 .InSequence(PISequence);
977
978 // Our mock pass does not invalidate IR.
979 EXPECT_CALL(CallbacksHandle,
980 runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))
981 .Times(0);
982
983 // No passes are skipped, so there should be no calls to
984 // runBeforeSkippedPass().
985 EXPECT_CALL(
986 CallbacksHandle,
987 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
988 .Times(0);
989
990 StringRef PipelineText = "test-transform";
991 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
992 << "Pipeline was: " << PipelineText;
993 PM.run(*M, AM);
994 }
995
TEST_F(CGSCCCallbacksTest,InstrumentedInvalidatingPasses)996 TEST_F(CGSCCCallbacksTest, InstrumentedInvalidatingPasses) {
997 CallbacksHandle.registerPassInstrumentation();
998 // Non-mock instrumentation not specifically mentioned below can be ignored.
999 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
1000 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
1001 CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)");
1002
1003 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
1004 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _))
1005 .WillOnce(DoAll(WithArgs<0, 1, 2, 3>(Invoke(PassHandle.invalidateSCC)),
1006 WithArgs<0, 1, 2>(Invoke(getAnalysisResult))));
1007
1008 // PassInstrumentation calls should happen in-sequence, in the same order
1009 // as passes/analyses are scheduled.
1010 ::testing::Sequence PISequence;
1011 EXPECT_CALL(CallbacksHandle,
1012 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
1013 .InSequence(PISequence);
1014 EXPECT_CALL(
1015 CallbacksHandle,
1016 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
1017 .InSequence(PISequence);
1018 EXPECT_CALL(
1019 CallbacksHandle,
1020 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
1021 .InSequence(PISequence);
1022 EXPECT_CALL(
1023 CallbacksHandle,
1024 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
1025 .InSequence(PISequence);
1026 EXPECT_CALL(CallbacksHandle,
1027 runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))
1028 .InSequence(PISequence);
1029 EXPECT_CALL(CallbacksHandle,
1030 runAfterPassInvalidated(HasNameRegex("^PassManager"), _))
1031 .InSequence(PISequence);
1032
1033 // Our mock pass does invalidate IR, thus normal runAfterPass is never called.
1034 EXPECT_CALL(CallbacksHandle,
1035 runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)"), _))
1036 .Times(0);
1037
1038 StringRef PipelineText = "test-transform";
1039 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
1040 << "Pipeline was: " << PipelineText;
1041 PM.run(*M, AM);
1042 }
1043
TEST_F(CGSCCCallbacksTest,InstrumentedSkippedPasses)1044 TEST_F(CGSCCCallbacksTest, InstrumentedSkippedPasses) {
1045 CallbacksHandle.registerPassInstrumentation();
1046 // Non-mock instrumentation run here can safely be ignored.
1047 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
1048 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
1049 CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)");
1050
1051 // Skip the pass by returning false.
1052 EXPECT_CALL(CallbacksHandle,
1053 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
1054 .WillOnce(Return(false));
1055
1056 EXPECT_CALL(
1057 CallbacksHandle,
1058 runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
1059 .Times(1);
1060
1061 // neither Analysis nor Pass are called.
1062 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)).Times(0);
1063 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _)).Times(0);
1064
1065 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis
1066 // as well.
1067 EXPECT_CALL(CallbacksHandle,
1068 runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), _))
1069 .Times(0);
1070 EXPECT_CALL(CallbacksHandle,
1071 runAfterPass(HasNameRegex("MockPassHandle"), _, _))
1072 .Times(0);
1073 EXPECT_CALL(CallbacksHandle,
1074 runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))
1075 .Times(0);
1076 EXPECT_CALL(CallbacksHandle,
1077 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))
1078 .Times(0);
1079 EXPECT_CALL(CallbacksHandle,
1080 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))
1081 .Times(0);
1082
1083 StringRef PipelineText = "test-transform";
1084 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
1085 << "Pipeline was: " << PipelineText;
1086 PM.run(*M, AM);
1087 }
1088
1089 /// Test parsing of the names of analysis utilities for our mock analysis
1090 /// for all IRUnits.
1091 ///
1092 /// We first require<>, then invalidate<> it, expecting the analysis to be run
1093 /// once and subsequently invalidated.
TEST_F(ModuleCallbacksTest,AnalysisUtilities)1094 TEST_F(ModuleCallbacksTest, AnalysisUtilities) {
1095 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
1096 EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _));
1097
1098 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
1099 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
1100 << "Pipeline was: " << PipelineText;
1101 PM.run(*M, AM);
1102 }
1103
TEST_F(CGSCCCallbacksTest,PassUtilities)1104 TEST_F(CGSCCCallbacksTest, PassUtilities) {
1105 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
1106 EXPECT_CALL(AnalysisHandle, invalidate(HasName("(foo)"), _, _));
1107
1108 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
1109 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
1110 << "Pipeline was: " << PipelineText;
1111 PM.run(*M, AM);
1112 }
1113
TEST_F(FunctionCallbacksTest,AnalysisUtilities)1114 TEST_F(FunctionCallbacksTest, AnalysisUtilities) {
1115 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));
1116 EXPECT_CALL(AnalysisHandle, invalidate(HasName("foo"), _, _));
1117
1118 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
1119 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
1120 << "Pipeline was: " << PipelineText;
1121 PM.run(*M, AM);
1122 }
1123
TEST_F(LoopCallbacksTest,PassUtilities)1124 TEST_F(LoopCallbacksTest, PassUtilities) {
1125 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
1126 EXPECT_CALL(AnalysisHandle, invalidate(HasName("loop"), _, _));
1127
1128 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
1129
1130 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
1131 << "Pipeline was: " << PipelineText;
1132 PM.run(*M, AM);
1133 }
1134
1135 /// Test parsing of the top-level pipeline.
1136 ///
1137 /// The ParseTopLevelPipeline callback takes over parsing of the entire pipeline
1138 /// from PassBuilder if it encounters an unknown pipeline entry at the top level
1139 /// (i.e., the first entry on the pipeline).
1140 /// This test parses a pipeline named 'another-pipeline', whose only elements
1141 /// may be the test-transform pass or the analysis utilities
TEST_F(ModuleCallbacksTest,ParseTopLevelPipeline)1142 TEST_F(ModuleCallbacksTest, ParseTopLevelPipeline) {
1143 PB.registerParseTopLevelPipelineCallback(
1144 [this](ModulePassManager &MPM,
1145 ArrayRef<PassBuilder::PipelineElement> Pipeline,
1146 bool DebugLogging) {
1147 auto &FirstName = Pipeline.front().Name;
1148 auto &InnerPipeline = Pipeline.front().InnerPipeline;
1149 if (FirstName == "another-pipeline") {
1150 for (auto &E : InnerPipeline) {
1151 if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis", E.Name,
1152 PM))
1153 continue;
1154
1155 if (E.Name == "test-transform") {
1156 PM.addPass(PassHandle.getPass());
1157 continue;
1158 }
1159 return false;
1160 }
1161 }
1162 return true;
1163 });
1164
1165 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
1166 EXPECT_CALL(PassHandle, run(HasName("<string>"), _))
1167 .WillOnce(Invoke(getAnalysisResult));
1168 EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _));
1169
1170 StringRef PipelineText =
1171 "another-pipeline(test-transform,invalidate<test-analysis>)";
1172 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
1173 << "Pipeline was: " << PipelineText;
1174 PM.run(*M, AM);
1175
1176 /// Test the negative case
1177 PipelineText = "another-pipeline(instcombine)";
1178 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Failed())
1179 << "Pipeline was: " << PipelineText;
1180 }
1181 } // end anonymous namespace
1182