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 /// Register a callback for analysis registration.
423 /// The callback is a function taking a reference to an AnalyisManager
424 /// object. When called, the callee gets to register its own analyses with
425 /// this PassBuilder instance.
426 PB
.registerAnalysisRegistrationCallback([this](AnalysisManagerT
&AM
) {
427 // Register our mock analysis
428 AM
.registerPass([this] { return AnalysisHandle
.getAnalysis(); });
431 /// Register a callback for pipeline parsing.
433 /// During parsing of a textual pipeline, the PassBuilder will call these
434 /// callbacks for each encountered pass name that it does not know. This
435 /// includes both simple pass names as well as names of sub-pipelines. In
436 /// the latter case, the InnerPipeline is not empty.
437 PB
.registerPipelineParsingCallback(
438 [this](StringRef Name
, PassManagerT
&PM
,
439 ArrayRef
<PassBuilder::PipelineElement
> InnerPipeline
) {
440 /// Handle parsing of the names of analysis utilities such as
441 /// require<test-analysis> and invalidate<test-analysis> for our
442 /// analysis mock handle
443 if (parseAnalysisUtilityPasses
<AnalysisT
>("test-analysis", Name
, PM
))
446 /// Parse the name of our pass mock handle
447 if (Name
== "test-transform") {
448 PM
.addPass(PassHandle
.getPass());
454 /// Register builtin analyses and cross-register the analysis proxies
455 PB
.registerModuleAnalyses(AM
);
456 PB
.registerCGSCCAnalyses(CGAM
);
457 PB
.registerFunctionAnalyses(FAM
);
458 PB
.registerLoopAnalyses(LAM
);
459 PB
.crossRegisterProxies(LAM
, FAM
, CGAM
, AM
);
463 using ModuleCallbacksTest
= PassBuilderCallbacksTest
<ModulePassManager
>;
464 using CGSCCCallbacksTest
= PassBuilderCallbacksTest
<CGSCCPassManager
>;
465 using FunctionCallbacksTest
= PassBuilderCallbacksTest
<FunctionPassManager
>;
466 using LoopCallbacksTest
= PassBuilderCallbacksTest
<LoopPassManager
>;
468 /// Test parsing of the name of our mock pass for all IRUnits.
470 /// The pass should by default run our mock analysis and then preserve it.
471 TEST_F(ModuleCallbacksTest
, Passes
) {
472 EXPECT_CALL(AnalysisHandle
, run(HasName("<string>"), _
));
473 EXPECT_CALL(PassHandle
, run(HasName("<string>"), _
))
474 .WillOnce(Invoke(getAnalysisResult
));
476 StringRef PipelineText
= "test-transform";
477 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
478 << "Pipeline was: " << PipelineText
;
483 TEST_F(ModuleCallbacksTest
, InstrumentedPasses
) {
484 EXPECT_CALL(AnalysisHandle
, run(HasName("<string>"), _
));
485 EXPECT_CALL(PassHandle
, run(HasName("<string>"), _
))
486 .WillOnce(Invoke(getAnalysisResult
));
488 CallbacksHandle
.registerPassInstrumentation();
489 // Non-mock instrumentation not specifically mentioned below can be ignored.
490 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
492 // PassInstrumentation calls should happen in-sequence, in the same order
493 // as passes/analyses are scheduled.
494 ::testing::Sequence PISequence
;
495 EXPECT_CALL(CallbacksHandle
, runBeforePass(HasNameRegex("MockPassHandle"),
496 HasName("<string>")))
497 .InSequence(PISequence
);
498 EXPECT_CALL(CallbacksHandle
,
499 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"),
500 HasName("<string>")))
501 .InSequence(PISequence
);
504 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("<string>")))
505 .InSequence(PISequence
);
506 EXPECT_CALL(CallbacksHandle
,
507 runAfterPass(HasNameRegex("MockPassHandle"), HasName("<string>")))
508 .InSequence(PISequence
);
510 StringRef PipelineText
= "test-transform";
511 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
512 << "Pipeline was: " << PipelineText
;
517 TEST_F(ModuleCallbacksTest
, InstrumentedSkippedPasses
) {
518 CallbacksHandle
.registerPassInstrumentation();
519 // Non-mock instrumentation run here can safely be ignored.
520 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
522 // Skip the pass by returning false.
523 EXPECT_CALL(CallbacksHandle
, runBeforePass(HasNameRegex("MockPassHandle"),
524 HasName("<string>")))
525 .WillOnce(Return(false));
527 EXPECT_CALL(AnalysisHandle
, run(HasName("<string>"), _
)).Times(0);
528 EXPECT_CALL(PassHandle
, run(HasName("<string>"), _
)).Times(0);
530 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis
532 EXPECT_CALL(CallbacksHandle
, runAfterPass(HasNameRegex("MockPassHandle"), _
))
534 EXPECT_CALL(CallbacksHandle
,
535 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _
))
537 EXPECT_CALL(CallbacksHandle
,
538 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _
))
541 StringRef PipelineText
= "test-transform";
542 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
543 << "Pipeline was: " << PipelineText
;
548 TEST_F(FunctionCallbacksTest
, Passes
) {
549 EXPECT_CALL(AnalysisHandle
, run(HasName("foo"), _
));
550 EXPECT_CALL(PassHandle
, run(HasName("foo"), _
))
551 .WillOnce(Invoke(getAnalysisResult
));
553 StringRef PipelineText
= "test-transform";
554 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
555 << "Pipeline was: " << PipelineText
;
559 TEST_F(FunctionCallbacksTest
, InstrumentedPasses
) {
560 CallbacksHandle
.registerPassInstrumentation();
561 // Non-mock instrumentation not specifically mentioned below can be ignored.
562 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
563 CallbacksHandle
.ignoreNonMockPassInstrumentation("foo");
565 EXPECT_CALL(AnalysisHandle
, run(HasName("foo"), _
));
566 EXPECT_CALL(PassHandle
, run(HasName("foo"), _
))
567 .WillOnce(Invoke(getAnalysisResult
));
569 // PassInstrumentation calls should happen in-sequence, in the same order
570 // as passes/analyses are scheduled.
571 ::testing::Sequence PISequence
;
572 EXPECT_CALL(CallbacksHandle
,
573 runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo")))
574 .InSequence(PISequence
);
577 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo")))
578 .InSequence(PISequence
);
581 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo")))
582 .InSequence(PISequence
);
583 EXPECT_CALL(CallbacksHandle
,
584 runAfterPass(HasNameRegex("MockPassHandle"), HasName("foo")))
585 .InSequence(PISequence
);
587 // Our mock pass does not invalidate IR.
588 EXPECT_CALL(CallbacksHandle
,
589 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
592 StringRef PipelineText
= "test-transform";
593 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
594 << "Pipeline was: " << PipelineText
;
598 TEST_F(FunctionCallbacksTest
, InstrumentedSkippedPasses
) {
599 CallbacksHandle
.registerPassInstrumentation();
600 // Non-mock instrumentation run here can safely be ignored.
601 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
602 CallbacksHandle
.ignoreNonMockPassInstrumentation("foo");
604 // Skip the pass by returning false.
605 EXPECT_CALL(CallbacksHandle
,
606 runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo")))
607 .WillOnce(Return(false));
609 EXPECT_CALL(AnalysisHandle
, run(HasName("foo"), _
)).Times(0);
610 EXPECT_CALL(PassHandle
, run(HasName("foo"), _
)).Times(0);
612 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis
614 EXPECT_CALL(CallbacksHandle
, runAfterPass(HasNameRegex("MockPassHandle"), _
))
616 EXPECT_CALL(CallbacksHandle
,
617 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
619 EXPECT_CALL(CallbacksHandle
, runAfterPass(HasNameRegex("MockPassHandle"), _
))
621 EXPECT_CALL(CallbacksHandle
,
622 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _
))
624 EXPECT_CALL(CallbacksHandle
,
625 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _
))
628 StringRef PipelineText
= "test-transform";
629 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
630 << "Pipeline was: " << PipelineText
;
634 TEST_F(LoopCallbacksTest
, Passes
) {
635 EXPECT_CALL(AnalysisHandle
, run(HasName("loop"), _
, _
));
636 EXPECT_CALL(PassHandle
, run(HasName("loop"), _
, _
, _
))
637 .WillOnce(WithArgs
<0, 1, 2>(Invoke(getAnalysisResult
)));
639 StringRef PipelineText
= "test-transform";
640 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
641 << "Pipeline was: " << PipelineText
;
645 TEST_F(LoopCallbacksTest
, InstrumentedPasses
) {
646 CallbacksHandle
.registerPassInstrumentation();
647 // Non-mock instrumentation not specifically mentioned below can be ignored.
648 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
649 CallbacksHandle
.ignoreNonMockPassInstrumentation("foo");
650 CallbacksHandle
.ignoreNonMockPassInstrumentation("loop");
652 EXPECT_CALL(AnalysisHandle
, run(HasName("loop"), _
, _
));
653 EXPECT_CALL(PassHandle
, run(HasName("loop"), _
, _
, _
))
654 .WillOnce(WithArgs
<0, 1, 2>(Invoke(getAnalysisResult
)));
656 // PassInstrumentation calls should happen in-sequence, in the same order
657 // as passes/analyses are scheduled.
658 ::testing::Sequence PISequence
;
659 EXPECT_CALL(CallbacksHandle
,
660 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
661 .InSequence(PISequence
);
664 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
665 .InSequence(PISequence
);
668 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
669 .InSequence(PISequence
);
670 EXPECT_CALL(CallbacksHandle
,
671 runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop")))
672 .InSequence(PISequence
);
674 // Our mock pass does not invalidate IR.
675 EXPECT_CALL(CallbacksHandle
,
676 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
679 StringRef PipelineText
= "test-transform";
680 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
681 << "Pipeline was: " << PipelineText
;
685 TEST_F(LoopCallbacksTest
, InstrumentedInvalidatingPasses
) {
686 CallbacksHandle
.registerPassInstrumentation();
687 // Non-mock instrumentation not specifically mentioned below can be ignored.
688 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
689 CallbacksHandle
.ignoreNonMockPassInstrumentation("foo");
690 CallbacksHandle
.ignoreNonMockPassInstrumentation("loop");
692 EXPECT_CALL(AnalysisHandle
, run(HasName("loop"), _
, _
));
693 EXPECT_CALL(PassHandle
, run(HasName("loop"), _
, _
, _
))
694 .WillOnce(DoAll(WithArgs
<0, 1, 2, 3>(Invoke(PassHandle
.invalidateLoop
)),
695 WithArgs
<0, 1, 2>(Invoke(getAnalysisResult
))));
697 // PassInstrumentation calls should happen in-sequence, in the same order
698 // as passes/analyses are scheduled.
699 ::testing::Sequence PISequence
;
700 EXPECT_CALL(CallbacksHandle
,
701 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
702 .InSequence(PISequence
);
705 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
706 .InSequence(PISequence
);
709 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
710 .InSequence(PISequence
);
711 EXPECT_CALL(CallbacksHandle
,
712 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
713 .InSequence(PISequence
);
714 EXPECT_CALL(CallbacksHandle
,
715 runAfterPassInvalidated(HasNameRegex("^PassManager")))
716 .InSequence(PISequence
);
718 // Our mock pass invalidates IR, thus normal runAfterPass is never called.
719 EXPECT_CALL(CallbacksHandle
,
720 runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop")))
723 StringRef PipelineText
= "test-transform";
724 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
725 << "Pipeline was: " << PipelineText
;
729 TEST_F(LoopCallbacksTest
, InstrumentedSkippedPasses
) {
730 CallbacksHandle
.registerPassInstrumentation();
731 // Non-mock instrumentation run here can safely be ignored.
732 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
733 CallbacksHandle
.ignoreNonMockPassInstrumentation("foo");
734 CallbacksHandle
.ignoreNonMockPassInstrumentation("loop");
736 // Skip the pass by returning false.
737 EXPECT_CALL(CallbacksHandle
,
738 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
739 .WillOnce(Return(false));
741 EXPECT_CALL(AnalysisHandle
, run(HasName("loop"), _
, _
)).Times(0);
742 EXPECT_CALL(PassHandle
, run(HasName("loop"), _
, _
, _
)).Times(0);
744 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis
746 EXPECT_CALL(CallbacksHandle
, runAfterPass(HasNameRegex("MockPassHandle"), _
))
748 EXPECT_CALL(CallbacksHandle
,
749 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
751 EXPECT_CALL(CallbacksHandle
,
752 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _
))
754 EXPECT_CALL(CallbacksHandle
,
755 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _
))
758 StringRef PipelineText
= "test-transform";
759 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
760 << "Pipeline was: " << PipelineText
;
764 TEST_F(CGSCCCallbacksTest
, Passes
) {
765 EXPECT_CALL(AnalysisHandle
, run(HasName("(foo)"), _
, _
));
766 EXPECT_CALL(PassHandle
, run(HasName("(foo)"), _
, _
, _
))
767 .WillOnce(WithArgs
<0, 1, 2>(Invoke(getAnalysisResult
)));
769 StringRef PipelineText
= "test-transform";
770 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
771 << "Pipeline was: " << PipelineText
;
775 TEST_F(CGSCCCallbacksTest
, InstrumentedPasses
) {
776 CallbacksHandle
.registerPassInstrumentation();
777 // Non-mock instrumentation not specifically mentioned below can be ignored.
778 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
779 CallbacksHandle
.ignoreNonMockPassInstrumentation("foo");
780 CallbacksHandle
.ignoreNonMockPassInstrumentation("(foo)");
782 EXPECT_CALL(AnalysisHandle
, run(HasName("(foo)"), _
, _
));
783 EXPECT_CALL(PassHandle
, run(HasName("(foo)"), _
, _
, _
))
784 .WillOnce(WithArgs
<0, 1, 2>(Invoke(getAnalysisResult
)));
786 // PassInstrumentation calls should happen in-sequence, in the same order
787 // as passes/analyses are scheduled.
788 ::testing::Sequence PISequence
;
789 EXPECT_CALL(CallbacksHandle
,
790 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
791 .InSequence(PISequence
);
794 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
795 .InSequence(PISequence
);
798 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
799 .InSequence(PISequence
);
800 EXPECT_CALL(CallbacksHandle
,
801 runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
802 .InSequence(PISequence
);
804 // Our mock pass does not invalidate IR.
805 EXPECT_CALL(CallbacksHandle
,
806 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
809 StringRef PipelineText
= "test-transform";
810 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
811 << "Pipeline was: " << PipelineText
;
815 TEST_F(CGSCCCallbacksTest
, InstrumentedInvalidatingPasses
) {
816 CallbacksHandle
.registerPassInstrumentation();
817 // Non-mock instrumentation not specifically mentioned below can be ignored.
818 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
819 CallbacksHandle
.ignoreNonMockPassInstrumentation("foo");
820 CallbacksHandle
.ignoreNonMockPassInstrumentation("(foo)");
822 EXPECT_CALL(AnalysisHandle
, run(HasName("(foo)"), _
, _
));
823 EXPECT_CALL(PassHandle
, run(HasName("(foo)"), _
, _
, _
))
824 .WillOnce(DoAll(WithArgs
<0, 1, 2, 3>(Invoke(PassHandle
.invalidateSCC
)),
825 WithArgs
<0, 1, 2>(Invoke(getAnalysisResult
))));
827 // PassInstrumentation calls should happen in-sequence, in the same order
828 // as passes/analyses are scheduled.
829 ::testing::Sequence PISequence
;
830 EXPECT_CALL(CallbacksHandle
,
831 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
832 .InSequence(PISequence
);
835 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
836 .InSequence(PISequence
);
839 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
840 .InSequence(PISequence
);
841 EXPECT_CALL(CallbacksHandle
,
842 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
843 .InSequence(PISequence
);
844 EXPECT_CALL(CallbacksHandle
,
845 runAfterPassInvalidated(HasNameRegex("^PassManager")))
846 .InSequence(PISequence
);
848 // Our mock pass does invalidate IR, thus normal runAfterPass is never called.
849 EXPECT_CALL(CallbacksHandle
,
850 runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
853 StringRef PipelineText
= "test-transform";
854 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
855 << "Pipeline was: " << PipelineText
;
859 TEST_F(CGSCCCallbacksTest
, InstrumentedSkippedPasses
) {
860 CallbacksHandle
.registerPassInstrumentation();
861 // Non-mock instrumentation run here can safely be ignored.
862 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
863 CallbacksHandle
.ignoreNonMockPassInstrumentation("foo");
864 CallbacksHandle
.ignoreNonMockPassInstrumentation("(foo)");
866 // Skip the pass by returning false.
867 EXPECT_CALL(CallbacksHandle
,
868 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
869 .WillOnce(Return(false));
871 // neither Analysis nor Pass are called.
872 EXPECT_CALL(AnalysisHandle
, run(HasName("(foo)"), _
, _
)).Times(0);
873 EXPECT_CALL(PassHandle
, run(HasName("(foo)"), _
, _
, _
)).Times(0);
875 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis
877 EXPECT_CALL(CallbacksHandle
, runAfterPass(HasNameRegex("MockPassHandle"), _
))
879 EXPECT_CALL(CallbacksHandle
,
880 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
882 EXPECT_CALL(CallbacksHandle
,
883 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _
))
885 EXPECT_CALL(CallbacksHandle
,
886 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _
))
889 StringRef PipelineText
= "test-transform";
890 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
891 << "Pipeline was: " << PipelineText
;
895 /// Test parsing of the names of analysis utilities for our mock analysis
898 /// We first require<>, then invalidate<> it, expecting the analysis to be run
899 /// once and subsequently invalidated.
900 TEST_F(ModuleCallbacksTest
, AnalysisUtilities
) {
901 EXPECT_CALL(AnalysisHandle
, run(HasName("<string>"), _
));
902 EXPECT_CALL(AnalysisHandle
, invalidate(HasName("<string>"), _
, _
));
904 StringRef PipelineText
= "require<test-analysis>,invalidate<test-analysis>";
905 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
906 << "Pipeline was: " << PipelineText
;
910 TEST_F(CGSCCCallbacksTest
, PassUtilities
) {
911 EXPECT_CALL(AnalysisHandle
, run(HasName("(foo)"), _
, _
));
912 EXPECT_CALL(AnalysisHandle
, invalidate(HasName("(foo)"), _
, _
));
914 StringRef PipelineText
= "require<test-analysis>,invalidate<test-analysis>";
915 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
916 << "Pipeline was: " << PipelineText
;
920 TEST_F(FunctionCallbacksTest
, AnalysisUtilities
) {
921 EXPECT_CALL(AnalysisHandle
, run(HasName("foo"), _
));
922 EXPECT_CALL(AnalysisHandle
, invalidate(HasName("foo"), _
, _
));
924 StringRef PipelineText
= "require<test-analysis>,invalidate<test-analysis>";
925 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
926 << "Pipeline was: " << PipelineText
;
930 TEST_F(LoopCallbacksTest
, PassUtilities
) {
931 EXPECT_CALL(AnalysisHandle
, run(HasName("loop"), _
, _
));
932 EXPECT_CALL(AnalysisHandle
, invalidate(HasName("loop"), _
, _
));
934 StringRef PipelineText
= "require<test-analysis>,invalidate<test-analysis>";
936 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
937 << "Pipeline was: " << PipelineText
;
941 /// Test parsing of the top-level pipeline.
943 /// The ParseTopLevelPipeline callback takes over parsing of the entire pipeline
944 /// from PassBuilder if it encounters an unknown pipeline entry at the top level
945 /// (i.e., the first entry on the pipeline).
946 /// This test parses a pipeline named 'another-pipeline', whose only elements
947 /// may be the test-transform pass or the analysis utilities
948 TEST_F(ModuleCallbacksTest
, ParseTopLevelPipeline
) {
949 PB
.registerParseTopLevelPipelineCallback([this](
950 ModulePassManager
&MPM
, ArrayRef
<PassBuilder::PipelineElement
> Pipeline
,
951 bool VerifyEachPass
, bool DebugLogging
) {
952 auto &FirstName
= Pipeline
.front().Name
;
953 auto &InnerPipeline
= Pipeline
.front().InnerPipeline
;
954 if (FirstName
== "another-pipeline") {
955 for (auto &E
: InnerPipeline
) {
956 if (parseAnalysisUtilityPasses
<AnalysisT
>("test-analysis", E
.Name
, PM
))
959 if (E
.Name
== "test-transform") {
960 PM
.addPass(PassHandle
.getPass());
969 EXPECT_CALL(AnalysisHandle
, run(HasName("<string>"), _
));
970 EXPECT_CALL(PassHandle
, run(HasName("<string>"), _
))
971 .WillOnce(Invoke(getAnalysisResult
));
972 EXPECT_CALL(AnalysisHandle
, invalidate(HasName("<string>"), _
, _
));
974 StringRef PipelineText
=
975 "another-pipeline(test-transform,invalidate<test-analysis>)";
976 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
977 << "Pipeline was: " << PipelineText
;
980 /// Test the negative case
981 PipelineText
= "another-pipeline(instcombine)";
982 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Failed())
983 << "Pipeline was: " << PipelineText
;
985 } // end anonymous namespace