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"
417 CallbacksHandle(), PB(nullptr, None
, &CallbacksHandle
.Callbacks
),
418 PM(true), LAM(true), FAM(true), CGAM(true), AM(true) {
420 /// Register a callback for analysis registration.
422 /// The callback is a function taking a reference to an AnalyisManager
423 /// object. When called, the callee gets to register its own analyses with
424 /// this PassBuilder instance.
425 PB
.registerAnalysisRegistrationCallback([this](AnalysisManagerT
&AM
) {
426 // Register our mock analysis
427 AM
.registerPass([this] { return AnalysisHandle
.getAnalysis(); });
430 /// Register a callback for pipeline parsing.
432 /// During parsing of a textual pipeline, the PassBuilder will call these
433 /// callbacks for each encountered pass name that it does not know. This
434 /// includes both simple pass names as well as names of sub-pipelines. In
435 /// the latter case, the InnerPipeline is not empty.
436 PB
.registerPipelineParsingCallback(
437 [this](StringRef Name
, PassManagerT
&PM
,
438 ArrayRef
<PassBuilder::PipelineElement
> InnerPipeline
) {
439 /// Handle parsing of the names of analysis utilities such as
440 /// require<test-analysis> and invalidate<test-analysis> for our
441 /// analysis mock handle
442 if (parseAnalysisUtilityPasses
<AnalysisT
>("test-analysis", Name
, PM
))
445 /// Parse the name of our pass mock handle
446 if (Name
== "test-transform") {
447 PM
.addPass(PassHandle
.getPass());
453 /// Register builtin analyses and cross-register the analysis proxies
454 PB
.registerModuleAnalyses(AM
);
455 PB
.registerCGSCCAnalyses(CGAM
);
456 PB
.registerFunctionAnalyses(FAM
);
457 PB
.registerLoopAnalyses(LAM
);
458 PB
.crossRegisterProxies(LAM
, FAM
, CGAM
, AM
);
462 using ModuleCallbacksTest
= PassBuilderCallbacksTest
<ModulePassManager
>;
463 using CGSCCCallbacksTest
= PassBuilderCallbacksTest
<CGSCCPassManager
>;
464 using FunctionCallbacksTest
= PassBuilderCallbacksTest
<FunctionPassManager
>;
465 using LoopCallbacksTest
= PassBuilderCallbacksTest
<LoopPassManager
>;
467 /// Test parsing of the name of our mock pass for all IRUnits.
469 /// The pass should by default run our mock analysis and then preserve it.
470 TEST_F(ModuleCallbacksTest
, Passes
) {
471 EXPECT_CALL(AnalysisHandle
, run(HasName("<string>"), _
));
472 EXPECT_CALL(PassHandle
, run(HasName("<string>"), _
))
473 .WillOnce(Invoke(getAnalysisResult
));
475 StringRef PipelineText
= "test-transform";
476 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
477 << "Pipeline was: " << PipelineText
;
482 TEST_F(ModuleCallbacksTest
, InstrumentedPasses
) {
483 EXPECT_CALL(AnalysisHandle
, run(HasName("<string>"), _
));
484 EXPECT_CALL(PassHandle
, run(HasName("<string>"), _
))
485 .WillOnce(Invoke(getAnalysisResult
));
487 CallbacksHandle
.registerPassInstrumentation();
488 // Non-mock instrumentation not specifically mentioned below can be ignored.
489 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
491 // PassInstrumentation calls should happen in-sequence, in the same order
492 // as passes/analyses are scheduled.
493 ::testing::Sequence PISequence
;
494 EXPECT_CALL(CallbacksHandle
, runBeforePass(HasNameRegex("MockPassHandle"),
495 HasName("<string>")))
496 .InSequence(PISequence
);
497 EXPECT_CALL(CallbacksHandle
,
498 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"),
499 HasName("<string>")))
500 .InSequence(PISequence
);
503 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("<string>")))
504 .InSequence(PISequence
);
505 EXPECT_CALL(CallbacksHandle
,
506 runAfterPass(HasNameRegex("MockPassHandle"), HasName("<string>")))
507 .InSequence(PISequence
);
509 StringRef PipelineText
= "test-transform";
510 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
511 << "Pipeline was: " << PipelineText
;
516 TEST_F(ModuleCallbacksTest
, InstrumentedSkippedPasses
) {
517 CallbacksHandle
.registerPassInstrumentation();
518 // Non-mock instrumentation run here can safely be ignored.
519 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
521 // Skip the pass by returning false.
522 EXPECT_CALL(CallbacksHandle
, runBeforePass(HasNameRegex("MockPassHandle"),
523 HasName("<string>")))
524 .WillOnce(Return(false));
526 EXPECT_CALL(AnalysisHandle
, run(HasName("<string>"), _
)).Times(0);
527 EXPECT_CALL(PassHandle
, run(HasName("<string>"), _
)).Times(0);
529 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis
531 EXPECT_CALL(CallbacksHandle
, runAfterPass(HasNameRegex("MockPassHandle"), _
))
533 EXPECT_CALL(CallbacksHandle
,
534 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _
))
536 EXPECT_CALL(CallbacksHandle
,
537 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _
))
540 StringRef PipelineText
= "test-transform";
541 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
542 << "Pipeline was: " << PipelineText
;
547 TEST_F(FunctionCallbacksTest
, Passes
) {
548 EXPECT_CALL(AnalysisHandle
, run(HasName("foo"), _
));
549 EXPECT_CALL(PassHandle
, run(HasName("foo"), _
))
550 .WillOnce(Invoke(getAnalysisResult
));
552 StringRef PipelineText
= "test-transform";
553 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
554 << "Pipeline was: " << PipelineText
;
558 TEST_F(FunctionCallbacksTest
, InstrumentedPasses
) {
559 CallbacksHandle
.registerPassInstrumentation();
560 // Non-mock instrumentation not specifically mentioned below can be ignored.
561 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
562 CallbacksHandle
.ignoreNonMockPassInstrumentation("foo");
564 EXPECT_CALL(AnalysisHandle
, run(HasName("foo"), _
));
565 EXPECT_CALL(PassHandle
, run(HasName("foo"), _
))
566 .WillOnce(Invoke(getAnalysisResult
));
568 // PassInstrumentation calls should happen in-sequence, in the same order
569 // as passes/analyses are scheduled.
570 ::testing::Sequence PISequence
;
571 EXPECT_CALL(CallbacksHandle
,
572 runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo")))
573 .InSequence(PISequence
);
576 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo")))
577 .InSequence(PISequence
);
580 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo")))
581 .InSequence(PISequence
);
582 EXPECT_CALL(CallbacksHandle
,
583 runAfterPass(HasNameRegex("MockPassHandle"), HasName("foo")))
584 .InSequence(PISequence
);
586 // Our mock pass does not invalidate IR.
587 EXPECT_CALL(CallbacksHandle
,
588 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
591 StringRef PipelineText
= "test-transform";
592 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
593 << "Pipeline was: " << PipelineText
;
597 TEST_F(FunctionCallbacksTest
, InstrumentedSkippedPasses
) {
598 CallbacksHandle
.registerPassInstrumentation();
599 // Non-mock instrumentation run here can safely be ignored.
600 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
601 CallbacksHandle
.ignoreNonMockPassInstrumentation("foo");
603 // Skip the pass by returning false.
604 EXPECT_CALL(CallbacksHandle
,
605 runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo")))
606 .WillOnce(Return(false));
608 EXPECT_CALL(AnalysisHandle
, run(HasName("foo"), _
)).Times(0);
609 EXPECT_CALL(PassHandle
, run(HasName("foo"), _
)).Times(0);
611 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis
613 EXPECT_CALL(CallbacksHandle
, runAfterPass(HasNameRegex("MockPassHandle"), _
))
615 EXPECT_CALL(CallbacksHandle
,
616 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
618 EXPECT_CALL(CallbacksHandle
, runAfterPass(HasNameRegex("MockPassHandle"), _
))
620 EXPECT_CALL(CallbacksHandle
,
621 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _
))
623 EXPECT_CALL(CallbacksHandle
,
624 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _
))
627 StringRef PipelineText
= "test-transform";
628 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
629 << "Pipeline was: " << PipelineText
;
633 TEST_F(LoopCallbacksTest
, Passes
) {
634 EXPECT_CALL(AnalysisHandle
, run(HasName("loop"), _
, _
));
635 EXPECT_CALL(PassHandle
, run(HasName("loop"), _
, _
, _
))
636 .WillOnce(WithArgs
<0, 1, 2>(Invoke(getAnalysisResult
)));
638 StringRef PipelineText
= "test-transform";
639 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
640 << "Pipeline was: " << PipelineText
;
644 TEST_F(LoopCallbacksTest
, InstrumentedPasses
) {
645 CallbacksHandle
.registerPassInstrumentation();
646 // Non-mock instrumentation not specifically mentioned below can be ignored.
647 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
648 CallbacksHandle
.ignoreNonMockPassInstrumentation("foo");
649 CallbacksHandle
.ignoreNonMockPassInstrumentation("loop");
651 EXPECT_CALL(AnalysisHandle
, run(HasName("loop"), _
, _
));
652 EXPECT_CALL(PassHandle
, run(HasName("loop"), _
, _
, _
))
653 .WillOnce(WithArgs
<0, 1, 2>(Invoke(getAnalysisResult
)));
655 // PassInstrumentation calls should happen in-sequence, in the same order
656 // as passes/analyses are scheduled.
657 ::testing::Sequence PISequence
;
658 EXPECT_CALL(CallbacksHandle
,
659 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
660 .InSequence(PISequence
);
663 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
664 .InSequence(PISequence
);
667 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
668 .InSequence(PISequence
);
669 EXPECT_CALL(CallbacksHandle
,
670 runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop")))
671 .InSequence(PISequence
);
673 // Our mock pass does not invalidate IR.
674 EXPECT_CALL(CallbacksHandle
,
675 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
678 StringRef PipelineText
= "test-transform";
679 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
680 << "Pipeline was: " << PipelineText
;
684 TEST_F(LoopCallbacksTest
, InstrumentedInvalidatingPasses
) {
685 CallbacksHandle
.registerPassInstrumentation();
686 // Non-mock instrumentation not specifically mentioned below can be ignored.
687 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
688 CallbacksHandle
.ignoreNonMockPassInstrumentation("foo");
689 CallbacksHandle
.ignoreNonMockPassInstrumentation("loop");
691 EXPECT_CALL(AnalysisHandle
, run(HasName("loop"), _
, _
));
692 EXPECT_CALL(PassHandle
, run(HasName("loop"), _
, _
, _
))
693 .WillOnce(DoAll(WithArgs
<0, 1, 2, 3>(Invoke(PassHandle
.invalidateLoop
)),
694 WithArgs
<0, 1, 2>(Invoke(getAnalysisResult
))));
696 // PassInstrumentation calls should happen in-sequence, in the same order
697 // as passes/analyses are scheduled.
698 ::testing::Sequence PISequence
;
699 EXPECT_CALL(CallbacksHandle
,
700 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
701 .InSequence(PISequence
);
704 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
705 .InSequence(PISequence
);
708 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
709 .InSequence(PISequence
);
710 EXPECT_CALL(CallbacksHandle
,
711 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
712 .InSequence(PISequence
);
713 EXPECT_CALL(CallbacksHandle
,
714 runAfterPassInvalidated(HasNameRegex("^PassManager")))
715 .InSequence(PISequence
);
717 // Our mock pass invalidates IR, thus normal runAfterPass is never called.
718 EXPECT_CALL(CallbacksHandle
,
719 runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop")))
722 StringRef PipelineText
= "test-transform";
723 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
724 << "Pipeline was: " << PipelineText
;
728 TEST_F(LoopCallbacksTest
, InstrumentedSkippedPasses
) {
729 CallbacksHandle
.registerPassInstrumentation();
730 // Non-mock instrumentation run here can safely be ignored.
731 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
732 CallbacksHandle
.ignoreNonMockPassInstrumentation("foo");
733 CallbacksHandle
.ignoreNonMockPassInstrumentation("loop");
735 // Skip the pass by returning false.
736 EXPECT_CALL(CallbacksHandle
,
737 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
738 .WillOnce(Return(false));
740 EXPECT_CALL(AnalysisHandle
, run(HasName("loop"), _
, _
)).Times(0);
741 EXPECT_CALL(PassHandle
, run(HasName("loop"), _
, _
, _
)).Times(0);
743 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis
745 EXPECT_CALL(CallbacksHandle
, runAfterPass(HasNameRegex("MockPassHandle"), _
))
747 EXPECT_CALL(CallbacksHandle
,
748 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
750 EXPECT_CALL(CallbacksHandle
,
751 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _
))
753 EXPECT_CALL(CallbacksHandle
,
754 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _
))
757 StringRef PipelineText
= "test-transform";
758 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
759 << "Pipeline was: " << PipelineText
;
763 TEST_F(CGSCCCallbacksTest
, Passes
) {
764 EXPECT_CALL(AnalysisHandle
, run(HasName("(foo)"), _
, _
));
765 EXPECT_CALL(PassHandle
, run(HasName("(foo)"), _
, _
, _
))
766 .WillOnce(WithArgs
<0, 1, 2>(Invoke(getAnalysisResult
)));
768 StringRef PipelineText
= "test-transform";
769 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
770 << "Pipeline was: " << PipelineText
;
774 TEST_F(CGSCCCallbacksTest
, InstrumentedPasses
) {
775 CallbacksHandle
.registerPassInstrumentation();
776 // Non-mock instrumentation not specifically mentioned below can be ignored.
777 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
778 CallbacksHandle
.ignoreNonMockPassInstrumentation("(foo)");
780 EXPECT_CALL(AnalysisHandle
, run(HasName("(foo)"), _
, _
));
781 EXPECT_CALL(PassHandle
, run(HasName("(foo)"), _
, _
, _
))
782 .WillOnce(WithArgs
<0, 1, 2>(Invoke(getAnalysisResult
)));
784 // PassInstrumentation calls should happen in-sequence, in the same order
785 // as passes/analyses are scheduled.
786 ::testing::Sequence PISequence
;
787 EXPECT_CALL(CallbacksHandle
,
788 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
789 .InSequence(PISequence
);
792 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
793 .InSequence(PISequence
);
796 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
797 .InSequence(PISequence
);
798 EXPECT_CALL(CallbacksHandle
,
799 runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
800 .InSequence(PISequence
);
802 // Our mock pass does not invalidate IR.
803 EXPECT_CALL(CallbacksHandle
,
804 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
807 StringRef PipelineText
= "test-transform";
808 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
809 << "Pipeline was: " << PipelineText
;
813 TEST_F(CGSCCCallbacksTest
, InstrumentedInvalidatingPasses
) {
814 CallbacksHandle
.registerPassInstrumentation();
815 // Non-mock instrumentation not specifically mentioned below can be ignored.
816 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
817 CallbacksHandle
.ignoreNonMockPassInstrumentation("(foo)");
819 EXPECT_CALL(AnalysisHandle
, run(HasName("(foo)"), _
, _
));
820 EXPECT_CALL(PassHandle
, run(HasName("(foo)"), _
, _
, _
))
821 .WillOnce(DoAll(WithArgs
<0, 1, 2, 3>(Invoke(PassHandle
.invalidateSCC
)),
822 WithArgs
<0, 1, 2>(Invoke(getAnalysisResult
))));
824 // PassInstrumentation calls should happen in-sequence, in the same order
825 // as passes/analyses are scheduled.
826 ::testing::Sequence PISequence
;
827 EXPECT_CALL(CallbacksHandle
,
828 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
829 .InSequence(PISequence
);
832 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
833 .InSequence(PISequence
);
836 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
837 .InSequence(PISequence
);
838 EXPECT_CALL(CallbacksHandle
,
839 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
840 .InSequence(PISequence
);
841 EXPECT_CALL(CallbacksHandle
,
842 runAfterPassInvalidated(HasNameRegex("^PassManager")))
843 .InSequence(PISequence
);
845 // Our mock pass does invalidate IR, thus normal runAfterPass is never called.
846 EXPECT_CALL(CallbacksHandle
,
847 runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
850 StringRef PipelineText
= "test-transform";
851 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
852 << "Pipeline was: " << PipelineText
;
856 TEST_F(CGSCCCallbacksTest
, InstrumentedSkippedPasses
) {
857 CallbacksHandle
.registerPassInstrumentation();
858 // Non-mock instrumentation run here can safely be ignored.
859 CallbacksHandle
.ignoreNonMockPassInstrumentation("<string>");
860 CallbacksHandle
.ignoreNonMockPassInstrumentation("(foo)");
862 // Skip the pass by returning false.
863 EXPECT_CALL(CallbacksHandle
,
864 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
865 .WillOnce(Return(false));
867 // neither Analysis nor Pass are called.
868 EXPECT_CALL(AnalysisHandle
, run(HasName("(foo)"), _
, _
)).Times(0);
869 EXPECT_CALL(PassHandle
, run(HasName("(foo)"), _
, _
, _
)).Times(0);
871 // As the pass is skipped there is no afterPass, beforeAnalysis/afterAnalysis
873 EXPECT_CALL(CallbacksHandle
, runAfterPass(HasNameRegex("MockPassHandle"), _
))
875 EXPECT_CALL(CallbacksHandle
,
876 runAfterPassInvalidated(HasNameRegex("MockPassHandle")))
878 EXPECT_CALL(CallbacksHandle
,
879 runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _
))
881 EXPECT_CALL(CallbacksHandle
,
882 runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _
))
885 StringRef PipelineText
= "test-transform";
886 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
887 << "Pipeline was: " << PipelineText
;
891 /// Test parsing of the names of analysis utilities for our mock analysis
894 /// We first require<>, then invalidate<> it, expecting the analysis to be run
895 /// once and subsequently invalidated.
896 TEST_F(ModuleCallbacksTest
, AnalysisUtilities
) {
897 EXPECT_CALL(AnalysisHandle
, run(HasName("<string>"), _
));
898 EXPECT_CALL(AnalysisHandle
, invalidate(HasName("<string>"), _
, _
));
900 StringRef PipelineText
= "require<test-analysis>,invalidate<test-analysis>";
901 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
902 << "Pipeline was: " << PipelineText
;
906 TEST_F(CGSCCCallbacksTest
, PassUtilities
) {
907 EXPECT_CALL(AnalysisHandle
, run(HasName("(foo)"), _
, _
));
908 EXPECT_CALL(AnalysisHandle
, invalidate(HasName("(foo)"), _
, _
));
910 StringRef PipelineText
= "require<test-analysis>,invalidate<test-analysis>";
911 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
912 << "Pipeline was: " << PipelineText
;
916 TEST_F(FunctionCallbacksTest
, AnalysisUtilities
) {
917 EXPECT_CALL(AnalysisHandle
, run(HasName("foo"), _
));
918 EXPECT_CALL(AnalysisHandle
, invalidate(HasName("foo"), _
, _
));
920 StringRef PipelineText
= "require<test-analysis>,invalidate<test-analysis>";
921 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
922 << "Pipeline was: " << PipelineText
;
926 TEST_F(LoopCallbacksTest
, PassUtilities
) {
927 EXPECT_CALL(AnalysisHandle
, run(HasName("loop"), _
, _
));
928 EXPECT_CALL(AnalysisHandle
, invalidate(HasName("loop"), _
, _
));
930 StringRef PipelineText
= "require<test-analysis>,invalidate<test-analysis>";
932 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
933 << "Pipeline was: " << PipelineText
;
937 /// Test parsing of the top-level pipeline.
939 /// The ParseTopLevelPipeline callback takes over parsing of the entire pipeline
940 /// from PassBuilder if it encounters an unknown pipeline entry at the top level
941 /// (i.e., the first entry on the pipeline).
942 /// This test parses a pipeline named 'another-pipeline', whose only elements
943 /// may be the test-transform pass or the analysis utilities
944 TEST_F(ModuleCallbacksTest
, ParseTopLevelPipeline
) {
945 PB
.registerParseTopLevelPipelineCallback([this](
946 ModulePassManager
&MPM
, ArrayRef
<PassBuilder::PipelineElement
> Pipeline
,
947 bool VerifyEachPass
, bool DebugLogging
) {
948 auto &FirstName
= Pipeline
.front().Name
;
949 auto &InnerPipeline
= Pipeline
.front().InnerPipeline
;
950 if (FirstName
== "another-pipeline") {
951 for (auto &E
: InnerPipeline
) {
952 if (parseAnalysisUtilityPasses
<AnalysisT
>("test-analysis", E
.Name
, PM
))
955 if (E
.Name
== "test-transform") {
956 PM
.addPass(PassHandle
.getPass());
965 EXPECT_CALL(AnalysisHandle
, run(HasName("<string>"), _
));
966 EXPECT_CALL(PassHandle
, run(HasName("<string>"), _
))
967 .WillOnce(Invoke(getAnalysisResult
));
968 EXPECT_CALL(AnalysisHandle
, invalidate(HasName("<string>"), _
, _
));
970 StringRef PipelineText
=
971 "another-pipeline(test-transform,invalidate<test-analysis>)";
972 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Succeeded())
973 << "Pipeline was: " << PipelineText
;
976 /// Test the negative case
977 PipelineText
= "another-pipeline(instcombine)";
978 ASSERT_THAT_ERROR(PB
.parsePassPipeline(PM
, PipelineText
, true), Failed())
979 << "Pipeline was: " << PipelineText
;
981 } // end anonymous namespace