1 //===- unittests/IR/PassBuilderCallbacksTest.cpp - PB Callback Tests --===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Testing/Support/Error.h"
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>
28 using testing::AnyNumber;
29 using testing::AtLeast;
30 using testing::DoDefault;
32 using testing::Return;
33 using testing::Expectation;
34 using testing::Invoke;
35 using testing::WithArgs;
38 /// A CRTP base for analysis mock handles
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 {
49 class Analysis : public AnalysisInfoMixin<Analysis> {
50 friend AnalysisInfoMixin<Analysis>;
51 friend MockAnalysisHandleBase;
52 static AnalysisKey Key;
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!");
63 friend MockAnalysisHandleBase;
67 Result(DerivedT &Handle) : Handle(&Handle) {}
70 // Forward invalidation events to the mock handle.
71 bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA,
72 typename AnalysisManagerT::Invalidator &Inv) {
73 return Handle->invalidate(IR, PA, Inv);
77 Result run(IRUnitT &IR, AnalysisManagerT &AM, ExtraArgTs... ExtraArgs) {
78 return Handle->run(IR, AM, ExtraArgs...);
82 Analysis getAnalysis() { return Analysis(static_cast<DerivedT &>(*this)); }
83 typename Analysis::Result getResult() {
84 return typename Analysis::Result(static_cast<DerivedT &>(*this));
86 static StringRef getName() { return llvm::getTypeName<DerivedT>(); }
89 // FIXME: MSVC seems unable to handle a lambda argument to Invoke from within
90 // the template, so we use a boring static function.
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>>();
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.)
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));
110 /// A CRTP base for pass mock handles
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;
121 template <typename DerivedT, typename IRUnitT,
122 typename AnalysisManagerT = AnalysisManager<IRUnitT>,
123 typename... ExtraArgTs>
124 class MockPassHandleBase {
126 class Pass : public PassInfoMixin<Pass> {
127 friend MockPassHandleBase;
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!");
137 PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM,
138 ExtraArgTs... ExtraArgs) {
139 return Handle->run(IR, AM, ExtraArgs...);
143 static StringRef getName() { return llvm::getTypeName<DerivedT>(); }
145 Pass getPass() { return Pass(static_cast<DerivedT &>(*this)); }
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.)
152 ON_CALL(static_cast<DerivedT &>(*this),
153 run(_, _, testing::Matcher<ExtraArgTs>(_)...))
154 .WillByDefault(Return(PreservedAnalyses::all()));
158 /// Mock handles for passes for the IRUnits Module, CGSCC, Function, Loop.
159 /// These handles define the appropriate run() mock interface for the respective
161 template <typename IRUnitT> struct MockPassHandle;
163 struct MockPassHandle<Loop>
164 : MockPassHandleBase<MockPassHandle<Loop>, Loop, LoopAnalysisManager,
165 LoopStandardAnalysisResults &, LPMUpdater &> {
167 PreservedAnalyses(Loop &, LoopAnalysisManager &,
168 LoopStandardAnalysisResults &, LPMUpdater &));
169 static void invalidateLoop(Loop &L, LoopAnalysisManager &,
170 LoopStandardAnalysisResults &,
171 LPMUpdater &Updater) {
172 Updater.markLoopAsDeleted(L, L.getName());
174 MockPassHandle() { setDefaults(); }
178 struct MockPassHandle<Function>
179 : MockPassHandleBase<MockPassHandle<Function>, Function> {
180 MOCK_METHOD2(run, PreservedAnalyses(Function &, FunctionAnalysisManager &));
182 MockPassHandle() { setDefaults(); }
186 struct MockPassHandle<LazyCallGraph::SCC>
187 : MockPassHandleBase<MockPassHandle<LazyCallGraph::SCC>, LazyCallGraph::SCC,
188 CGSCCAnalysisManager, LazyCallGraph &,
189 CGSCCUpdateResult &> {
191 PreservedAnalyses(LazyCallGraph::SCC &, CGSCCAnalysisManager &,
192 LazyCallGraph &G, CGSCCUpdateResult &UR));
194 static void invalidateSCC(LazyCallGraph::SCC &C, CGSCCAnalysisManager &,
195 LazyCallGraph &, CGSCCUpdateResult &UR) {
196 UR.InvalidatedSCCs.insert(&C);
199 MockPassHandle() { setDefaults(); }
203 struct MockPassHandle<Module>
204 : MockPassHandleBase<MockPassHandle<Module>, Module> {
205 MOCK_METHOD2(run, PreservedAnalyses(Module &, ModuleAnalysisManager &));
207 MockPassHandle() { setDefaults(); }
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;
215 struct MockAnalysisHandle<Loop>
216 : MockAnalysisHandleBase<MockAnalysisHandle<Loop>, Loop,
218 LoopStandardAnalysisResults &> {
220 MOCK_METHOD3_T(run, typename Analysis::Result(Loop &, LoopAnalysisManager &,
221 LoopStandardAnalysisResults &));
223 MOCK_METHOD3_T(invalidate, bool(Loop &, const PreservedAnalyses &,
224 LoopAnalysisManager::Invalidator &));
226 MockAnalysisHandle<Loop>() { this->setDefaults(); }
230 struct MockAnalysisHandle<Function>
231 : MockAnalysisHandleBase<MockAnalysisHandle<Function>, Function> {
232 MOCK_METHOD2(run, Analysis::Result(Function &, FunctionAnalysisManager &));
234 MOCK_METHOD3(invalidate, bool(Function &, const PreservedAnalyses &,
235 FunctionAnalysisManager::Invalidator &));
237 MockAnalysisHandle<Function>() { setDefaults(); }
241 struct MockAnalysisHandle<LazyCallGraph::SCC>
242 : MockAnalysisHandleBase<MockAnalysisHandle<LazyCallGraph::SCC>,
243 LazyCallGraph::SCC, CGSCCAnalysisManager,
245 MOCK_METHOD3(run, Analysis::Result(LazyCallGraph::SCC &,
246 CGSCCAnalysisManager &, LazyCallGraph &));
248 MOCK_METHOD3(invalidate, bool(LazyCallGraph::SCC &, const PreservedAnalyses &,
249 CGSCCAnalysisManager::Invalidator &));
251 MockAnalysisHandle<LazyCallGraph::SCC>() { setDefaults(); }
255 struct MockAnalysisHandle<Module>
256 : MockAnalysisHandleBase<MockAnalysisHandle<Module>, Module> {
257 MOCK_METHOD2(run, Analysis::Result(Module &, ModuleAnalysisManager &));
259 MOCK_METHOD3(invalidate, bool(Module &, const PreservedAnalyses &,
260 ModuleAnalysisManager::Invalidator &));
262 MockAnalysisHandle<Module>() { setDefaults(); }
265 static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
267 return parseAssemblyString(IR, Err, C);
270 /// Helper for HasName matcher that returns getName both for IRUnit and
271 /// for IRUnit pointer wrapper into llvm::Any (wrapped by PassInstrumentation).
272 template <typename IRUnitT> std::string getName(const IRUnitT &IR) {
276 template <> std::string getName(const StringRef &name) { return name; }
278 template <> std::string getName(const llvm::Any &WrappedIR) {
279 if (any_isa<const Module *>(WrappedIR))
280 return any_cast<const Module *>(WrappedIR)->getName().str();
281 if (any_isa<const Function *>(WrappedIR))
282 return any_cast<const Function *>(WrappedIR)->getName().str();
283 if (any_isa<const Loop *>(WrappedIR))
284 return any_cast<const Loop *>(WrappedIR)->getName().str();
285 if (any_isa<const LazyCallGraph::SCC *>(WrappedIR))
286 return any_cast<const LazyCallGraph::SCC *>(WrappedIR)->getName();
289 /// Define a custom matcher for objects which support a 'getName' method.
291 /// LLVM often has IR objects or analysis objects which expose a name
292 /// and in tests it is convenient to match these by name for readability.
293 /// Usually, this name is either a StringRef or a plain std::string. This
294 /// matcher supports any type exposing a getName() method of this form whose
295 /// return value is compatible with an std::ostream. For StringRef, this uses
296 /// the shift operator defined above.
298 /// It should be used as:
300 /// HasName("my_function")
302 /// No namespace or other qualification is required.
303 MATCHER_P(HasName, Name, "") {
304 *result_listener << "has name '" << getName(arg) << "'";
305 return Name == getName(arg);
308 MATCHER_P(HasNameRegex, Name, "") {
309 *result_listener << "has name '" << getName(arg) << "'";
311 return r.match(getName(arg));
314 struct MockPassInstrumentationCallbacks {
315 PassInstrumentationCallbacks Callbacks;
317 MockPassInstrumentationCallbacks() {
318 ON_CALL(*this, runBeforePass(_, _)).WillByDefault(Return(true));
320 MOCK_METHOD2(runBeforePass, bool(StringRef PassID, llvm::Any));
321 MOCK_METHOD2(runAfterPass, void(StringRef PassID, llvm::Any));
322 MOCK_METHOD1(runAfterPassInvalidated, void(StringRef PassID));
323 MOCK_METHOD2(runBeforeAnalysis, void(StringRef PassID, llvm::Any));
324 MOCK_METHOD2(runAfterAnalysis, void(StringRef PassID, llvm::Any));
326 void registerPassInstrumentation() {
327 Callbacks.registerBeforePassCallback([this](StringRef P, llvm::Any IR) {
328 return this->runBeforePass(P, IR);
330 Callbacks.registerAfterPassCallback(
331 [this](StringRef P, llvm::Any IR) { this->runAfterPass(P, IR); });
332 Callbacks.registerAfterPassInvalidatedCallback(
333 [this](StringRef P) { this->runAfterPassInvalidated(P); });
334 Callbacks.registerBeforeAnalysisCallback([this](StringRef P, llvm::Any IR) {
335 return this->runBeforeAnalysis(P, IR);
337 Callbacks.registerAfterAnalysisCallback(
338 [this](StringRef P, llvm::Any IR) { this->runAfterAnalysis(P, IR); });
341 void ignoreNonMockPassInstrumentation(StringRef IRName) {
342 // Generic EXPECT_CALLs are needed to match instrumentation on unimportant
343 // parts of a pipeline that we do not care about (e.g. various passes added
344 // by default by PassBuilder - Verifier pass etc).
345 // Make sure to avoid ignoring Mock passes/analysis, we definitely want
346 // to check these explicitly.
348 runBeforePass(Not(HasNameRegex("Mock")), HasName(IRName)))
350 EXPECT_CALL(*this, runAfterPass(Not(HasNameRegex("Mock")), HasName(IRName)))
353 runBeforeAnalysis(Not(HasNameRegex("Mock")), HasName(IRName)))
356 runAfterAnalysis(Not(HasNameRegex("Mock")), HasName(IRName)))
361 template <typename PassManagerT> class PassBuilderCallbacksTest;
363 /// This test fixture is shared between all the actual tests below and
364 /// takes care of setting up appropriate defaults.
366 /// The template specialization serves to extract the IRUnit and AM types from
367 /// the given PassManagerT.
368 template <typename TestIRUnitT, typename... ExtraPassArgTs,
369 typename... ExtraAnalysisArgTs>
370 class PassBuilderCallbacksTest<PassManager<
371 TestIRUnitT, AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>,
372 ExtraPassArgTs...>> : public testing::Test {
374 using IRUnitT = TestIRUnitT;
375 using AnalysisManagerT = AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>;
377 PassManager<TestIRUnitT, AnalysisManagerT, ExtraPassArgTs...>;
378 using AnalysisT = typename MockAnalysisHandle<IRUnitT>::Analysis;
381 std::unique_ptr<Module> M;
383 MockPassInstrumentationCallbacks CallbacksHandle;
386 ModulePassManager PM;
387 LoopAnalysisManager LAM;
388 FunctionAnalysisManager FAM;
389 CGSCCAnalysisManager CGAM;
390 ModuleAnalysisManager AM;
392 MockPassHandle<IRUnitT> PassHandle;
393 MockAnalysisHandle<IRUnitT> AnalysisHandle;
395 static PreservedAnalyses getAnalysisResult(IRUnitT &U, AnalysisManagerT &AM,
396 ExtraAnalysisArgTs &&... Args) {
397 (void)AM.template getResult<AnalysisT>(
398 U, std::forward<ExtraAnalysisArgTs>(Args)...);
399 return PreservedAnalyses::all();
402 PassBuilderCallbacksTest()
404 "declare void @bar()\n"
405 "define void @foo(i32 %n) {\n"
409 " %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]\n"
410 " %iv.next = add i32 %iv, 1\n"
411 " tail call void @bar()\n"
412 " %cmp = icmp eq i32 %iv, %n\n"
413 " br i1 %cmp, label %exit, label %loop\n"
418 PB(nullptr, PipelineTuningOptions(), None, &CallbacksHandle.Callbacks),
419 PM(true), LAM(true), FAM(true), CGAM(true), AM(true) {
421 EXPECT_TRUE(&CallbacksHandle.Callbacks ==
422 PB.getPassInstrumentationCallbacks());
424 /// Register a callback for analysis registration.
426 /// The callback is a function taking a reference to an AnalyisManager
427 /// object. When called, the callee gets to register its own analyses with
428 /// this PassBuilder instance.
429 PB.registerAnalysisRegistrationCallback([this](AnalysisManagerT &AM) {
430 // Register our mock analysis
431 AM.registerPass([this] { return AnalysisHandle.getAnalysis(); });
434 /// Register a callback for pipeline parsing.
436 /// During parsing of a textual pipeline, the PassBuilder will call these
437 /// callbacks for each encountered pass name that it does not know. This
438 /// includes both simple pass names as well as names of sub-pipelines. In
439 /// the latter case, the InnerPipeline is not empty.
440 PB.registerPipelineParsingCallback(
441 [this](StringRef Name, PassManagerT &PM,
442 ArrayRef<PassBuilder::PipelineElement> InnerPipeline) {
443 /// Handle parsing of the names of analysis utilities such as
444 /// require<test-analysis> and invalidate<test-analysis> for our
445 /// analysis mock handle
446 if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis", Name, PM))
449 /// Parse the name of our pass mock handle
450 if (Name == "test-transform") {
451 PM.addPass(PassHandle.getPass());
457 /// Register builtin analyses and cross-register the analysis proxies
458 PB.registerModuleAnalyses(AM);
459 PB.registerCGSCCAnalyses(CGAM);
460 PB.registerFunctionAnalyses(FAM);
461 PB.registerLoopAnalyses(LAM);
462 PB.crossRegisterProxies(LAM, FAM, CGAM, AM);
466 using ModuleCallbacksTest = PassBuilderCallbacksTest<ModulePassManager>;
467 using CGSCCCallbacksTest = PassBuilderCallbacksTest<CGSCCPassManager>;
468 using FunctionCallbacksTest = PassBuilderCallbacksTest<FunctionPassManager>;
469 using LoopCallbacksTest = PassBuilderCallbacksTest<LoopPassManager>;
471 /// Test parsing of the name of our mock pass for all IRUnits.
473 /// The pass should by default run our mock analysis and then preserve it.
474 TEST_F(ModuleCallbacksTest, Passes) {
475 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
476 EXPECT_CALL(PassHandle, run(HasName("<string>"), _))
477 .WillOnce(Invoke(getAnalysisResult));
479 StringRef PipelineText = "test-transform";
480 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
481 << "Pipeline was: " << PipelineText;
486 TEST_F(ModuleCallbacksTest, InstrumentedPasses) {
487 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
488 EXPECT_CALL(PassHandle, run(HasName("<string>"), _))
489 .WillOnce(Invoke(getAnalysisResult));
491 CallbacksHandle.registerPassInstrumentation();
492 // Non-mock instrumentation not specifically mentioned below can be ignored.
493 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
495 // PassInstrumentation calls should happen in-sequence, in the same order
496 // as passes/analyses are scheduled.
497 ::testing::Sequence PISequence;
498 EXPECT_CALL(CallbacksHandle, runBeforePass(HasNameRegex("MockPassHandle"),
499 HasName("<string>")))
500 .InSequence(PISequence);
501 EXPECT_CALL(CallbacksHandle,
502 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"),
503 HasName("<string>")))
504 .InSequence(PISequence);
507 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("<string>")))
508 .InSequence(PISequence);
509 EXPECT_CALL(CallbacksHandle,
510 runAfterPass(HasNameRegex("MockPassHandle"), HasName("<string>")))
511 .InSequence(PISequence);
513 StringRef PipelineText = "test-transform";
514 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
515 << "Pipeline was: " << PipelineText;
520 TEST_F(ModuleCallbacksTest, InstrumentedSkippedPasses) {
521 CallbacksHandle.registerPassInstrumentation();
522 // Non-mock instrumentation run here can safely be ignored.
523 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
525 // Skip the pass by returning false.
526 EXPECT_CALL(CallbacksHandle, runBeforePass(HasNameRegex("MockPassHandle"),
527 HasName("<string>")))
528 .WillOnce(Return(false));
530 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)).Times(0);
531 EXPECT_CALL(PassHandle, run(HasName("<string>"), _)).Times(0);
533 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis
535 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _))
537 EXPECT_CALL(CallbacksHandle,
538 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))
540 EXPECT_CALL(CallbacksHandle,
541 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))
544 StringRef PipelineText = "test-transform";
545 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
546 << "Pipeline was: " << PipelineText;
551 TEST_F(FunctionCallbacksTest, Passes) {
552 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));
553 EXPECT_CALL(PassHandle, run(HasName("foo"), _))
554 .WillOnce(Invoke(getAnalysisResult));
556 StringRef PipelineText = "test-transform";
557 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
558 << "Pipeline was: " << PipelineText;
562 TEST_F(FunctionCallbacksTest, InstrumentedPasses) {
563 CallbacksHandle.registerPassInstrumentation();
564 // Non-mock instrumentation not specifically mentioned below can be ignored.
565 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
566 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
568 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));
569 EXPECT_CALL(PassHandle, run(HasName("foo"), _))
570 .WillOnce(Invoke(getAnalysisResult));
572 // PassInstrumentation calls should happen in-sequence, in the same order
573 // as passes/analyses are scheduled.
574 ::testing::Sequence PISequence;
575 EXPECT_CALL(CallbacksHandle,
576 runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo")))
577 .InSequence(PISequence);
580 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo")))
581 .InSequence(PISequence);
584 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo")))
585 .InSequence(PISequence);
586 EXPECT_CALL(CallbacksHandle,
587 runAfterPass(HasNameRegex("MockPassHandle"), HasName("foo")))
588 .InSequence(PISequence);
590 // Our mock pass does not invalidate IR.
591 EXPECT_CALL(CallbacksHandle,
592 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
595 StringRef PipelineText = "test-transform";
596 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
597 << "Pipeline was: " << PipelineText;
601 TEST_F(FunctionCallbacksTest, InstrumentedSkippedPasses) {
602 CallbacksHandle.registerPassInstrumentation();
603 // Non-mock instrumentation run here can safely be ignored.
604 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
605 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
607 // Skip the pass by returning false.
608 EXPECT_CALL(CallbacksHandle,
609 runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo")))
610 .WillOnce(Return(false));
612 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _)).Times(0);
613 EXPECT_CALL(PassHandle, run(HasName("foo"), _)).Times(0);
615 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis
617 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _))
619 EXPECT_CALL(CallbacksHandle,
620 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
622 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _))
624 EXPECT_CALL(CallbacksHandle,
625 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))
627 EXPECT_CALL(CallbacksHandle,
628 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))
631 StringRef PipelineText = "test-transform";
632 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
633 << "Pipeline was: " << PipelineText;
637 TEST_F(LoopCallbacksTest, Passes) {
638 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
639 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))
640 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
642 StringRef PipelineText = "test-transform";
643 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
644 << "Pipeline was: " << PipelineText;
648 TEST_F(LoopCallbacksTest, InstrumentedPasses) {
649 CallbacksHandle.registerPassInstrumentation();
650 // Non-mock instrumentation not specifically mentioned below can be ignored.
651 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
652 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
653 CallbacksHandle.ignoreNonMockPassInstrumentation("loop");
655 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
656 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))
657 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
659 // PassInstrumentation calls should happen in-sequence, in the same order
660 // as passes/analyses are scheduled.
661 ::testing::Sequence PISequence;
662 EXPECT_CALL(CallbacksHandle,
663 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
664 .InSequence(PISequence);
667 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
668 .InSequence(PISequence);
671 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
672 .InSequence(PISequence);
673 EXPECT_CALL(CallbacksHandle,
674 runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop")))
675 .InSequence(PISequence);
677 // Our mock pass does not invalidate IR.
678 EXPECT_CALL(CallbacksHandle,
679 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
682 StringRef PipelineText = "test-transform";
683 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
684 << "Pipeline was: " << PipelineText;
688 TEST_F(LoopCallbacksTest, InstrumentedInvalidatingPasses) {
689 CallbacksHandle.registerPassInstrumentation();
690 // Non-mock instrumentation not specifically mentioned below can be ignored.
691 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
692 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
693 CallbacksHandle.ignoreNonMockPassInstrumentation("loop");
695 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
696 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))
697 .WillOnce(DoAll(WithArgs<0, 1, 2, 3>(Invoke(PassHandle.invalidateLoop)),
698 WithArgs<0, 1, 2>(Invoke(getAnalysisResult))));
700 // PassInstrumentation calls should happen in-sequence, in the same order
701 // as passes/analyses are scheduled.
702 ::testing::Sequence PISequence;
703 EXPECT_CALL(CallbacksHandle,
704 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
705 .InSequence(PISequence);
708 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
709 .InSequence(PISequence);
712 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
713 .InSequence(PISequence);
714 EXPECT_CALL(CallbacksHandle,
715 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
716 .InSequence(PISequence);
717 EXPECT_CALL(CallbacksHandle,
718 runAfterPassInvalidated(HasNameRegex("^PassManager")))
719 .InSequence(PISequence);
721 // Our mock pass invalidates IR, thus normal runAfterPass is never called.
722 EXPECT_CALL(CallbacksHandle,
723 runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop")))
726 StringRef PipelineText = "test-transform";
727 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
728 << "Pipeline was: " << PipelineText;
732 TEST_F(LoopCallbacksTest, InstrumentedSkippedPasses) {
733 CallbacksHandle.registerPassInstrumentation();
734 // Non-mock instrumentation run here can safely be ignored.
735 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
736 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
737 CallbacksHandle.ignoreNonMockPassInstrumentation("loop");
739 // Skip the pass by returning false.
740 EXPECT_CALL(CallbacksHandle,
741 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
742 .WillOnce(Return(false));
744 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)).Times(0);
745 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _)).Times(0);
747 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis
749 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _))
751 EXPECT_CALL(CallbacksHandle,
752 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
754 EXPECT_CALL(CallbacksHandle,
755 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))
757 EXPECT_CALL(CallbacksHandle,
758 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))
761 StringRef PipelineText = "test-transform";
762 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
763 << "Pipeline was: " << PipelineText;
767 TEST_F(CGSCCCallbacksTest, Passes) {
768 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
769 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _))
770 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
772 StringRef PipelineText = "test-transform";
773 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
774 << "Pipeline was: " << PipelineText;
778 TEST_F(CGSCCCallbacksTest, InstrumentedPasses) {
779 CallbacksHandle.registerPassInstrumentation();
780 // Non-mock instrumentation not specifically mentioned below can be ignored.
781 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
782 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
783 CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)");
785 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
786 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _))
787 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
789 // PassInstrumentation calls should happen in-sequence, in the same order
790 // as passes/analyses are scheduled.
791 ::testing::Sequence PISequence;
792 EXPECT_CALL(CallbacksHandle,
793 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
794 .InSequence(PISequence);
797 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
798 .InSequence(PISequence);
801 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
802 .InSequence(PISequence);
803 EXPECT_CALL(CallbacksHandle,
804 runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
805 .InSequence(PISequence);
807 // Our mock pass does not invalidate IR.
808 EXPECT_CALL(CallbacksHandle,
809 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
812 StringRef PipelineText = "test-transform";
813 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
814 << "Pipeline was: " << PipelineText;
818 TEST_F(CGSCCCallbacksTest, InstrumentedInvalidatingPasses) {
819 CallbacksHandle.registerPassInstrumentation();
820 // Non-mock instrumentation not specifically mentioned below can be ignored.
821 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
822 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
823 CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)");
825 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
826 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _))
827 .WillOnce(DoAll(WithArgs<0, 1, 2, 3>(Invoke(PassHandle.invalidateSCC)),
828 WithArgs<0, 1, 2>(Invoke(getAnalysisResult))));
830 // PassInstrumentation calls should happen in-sequence, in the same order
831 // as passes/analyses are scheduled.
832 ::testing::Sequence PISequence;
833 EXPECT_CALL(CallbacksHandle,
834 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
835 .InSequence(PISequence);
838 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
839 .InSequence(PISequence);
842 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
843 .InSequence(PISequence);
844 EXPECT_CALL(CallbacksHandle,
845 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
846 .InSequence(PISequence);
847 EXPECT_CALL(CallbacksHandle,
848 runAfterPassInvalidated(HasNameRegex("^PassManager")))
849 .InSequence(PISequence);
851 // Our mock pass does invalidate IR, thus normal runAfterPass is never called.
852 EXPECT_CALL(CallbacksHandle,
853 runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
856 StringRef PipelineText = "test-transform";
857 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
858 << "Pipeline was: " << PipelineText;
862 TEST_F(CGSCCCallbacksTest, InstrumentedSkippedPasses) {
863 CallbacksHandle.registerPassInstrumentation();
864 // Non-mock instrumentation run here can safely be ignored.
865 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
866 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
867 CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)");
869 // Skip the pass by returning false.
870 EXPECT_CALL(CallbacksHandle,
871 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
872 .WillOnce(Return(false));
874 // neither Analysis nor Pass are called.
875 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)).Times(0);
876 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _)).Times(0);
878 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis
880 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _))
882 EXPECT_CALL(CallbacksHandle,
883 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
885 EXPECT_CALL(CallbacksHandle,
886 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))
888 EXPECT_CALL(CallbacksHandle,
889 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))
892 StringRef PipelineText = "test-transform";
893 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
894 << "Pipeline was: " << PipelineText;
898 /// Test parsing of the names of analysis utilities for our mock analysis
901 /// We first require<>, then invalidate<> it, expecting the analysis to be run
902 /// once and subsequently invalidated.
903 TEST_F(ModuleCallbacksTest, AnalysisUtilities) {
904 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
905 EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _));
907 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
908 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
909 << "Pipeline was: " << PipelineText;
913 TEST_F(CGSCCCallbacksTest, PassUtilities) {
914 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
915 EXPECT_CALL(AnalysisHandle, invalidate(HasName("(foo)"), _, _));
917 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
918 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
919 << "Pipeline was: " << PipelineText;
923 TEST_F(FunctionCallbacksTest, AnalysisUtilities) {
924 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));
925 EXPECT_CALL(AnalysisHandle, invalidate(HasName("foo"), _, _));
927 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
928 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
929 << "Pipeline was: " << PipelineText;
933 TEST_F(LoopCallbacksTest, PassUtilities) {
934 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
935 EXPECT_CALL(AnalysisHandle, invalidate(HasName("loop"), _, _));
937 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
939 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
940 << "Pipeline was: " << PipelineText;
944 /// Test parsing of the top-level pipeline.
946 /// The ParseTopLevelPipeline callback takes over parsing of the entire pipeline
947 /// from PassBuilder if it encounters an unknown pipeline entry at the top level
948 /// (i.e., the first entry on the pipeline).
949 /// This test parses a pipeline named 'another-pipeline', whose only elements
950 /// may be the test-transform pass or the analysis utilities
951 TEST_F(ModuleCallbacksTest, ParseTopLevelPipeline) {
952 PB.registerParseTopLevelPipelineCallback([this](
953 ModulePassManager &MPM, ArrayRef<PassBuilder::PipelineElement> Pipeline,
954 bool VerifyEachPass, bool DebugLogging) {
955 auto &FirstName = Pipeline.front().Name;
956 auto &InnerPipeline = Pipeline.front().InnerPipeline;
957 if (FirstName == "another-pipeline") {
958 for (auto &E : InnerPipeline) {
959 if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis", E.Name, PM))
962 if (E.Name == "test-transform") {
963 PM.addPass(PassHandle.getPass());
972 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
973 EXPECT_CALL(PassHandle, run(HasName("<string>"), _))
974 .WillOnce(Invoke(getAnalysisResult));
975 EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _));
977 StringRef PipelineText =
978 "another-pipeline(test-transform,invalidate<test-analysis>)";
979 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Succeeded())
980 << "Pipeline was: " << PipelineText;
983 /// Test the negative case
984 PipelineText = "another-pipeline(instcombine)";
985 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText, true), Failed())
986 << "Pipeline was: " << PipelineText;
988 } // end anonymous namespace