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

source code of llvm/unittests/IR/PassBuilderCallbacksTest.cpp