blob: 024e7d601b23dfff0ab4c4b01bfef7d2ebbbe1f3 [file] [log] [blame]
Philip Pfaffe730f2f92017-07-10 10:57:55 +00001//===- unittests/IR/PassBuilderCallbacksTest.cpp - PB Callback Tests --===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Fedor Sergeevee8d31c2018-09-20 17:08:45 +000010#include <functional>
Philip Pfaffe730f2f92017-07-10 10:57:55 +000011#include <gmock/gmock.h>
12#include <gtest/gtest.h>
Fedor Sergeevee8d31c2018-09-20 17:08:45 +000013#include <llvm/ADT/Any.h>
Philip Pfaffe730f2f92017-07-10 10:57:55 +000014#include <llvm/Analysis/CGSCCPassManager.h>
15#include <llvm/Analysis/LoopAnalysisManager.h>
16#include <llvm/AsmParser/Parser.h>
17#include <llvm/IR/LLVMContext.h>
Fedor Sergeevee8d31c2018-09-20 17:08:45 +000018#include <llvm/IR/PassInstrumentation.h>
Philip Pfaffe730f2f92017-07-10 10:57:55 +000019#include <llvm/IR/PassManager.h>
20#include <llvm/Passes/PassBuilder.h>
Fedor Sergeevee8d31c2018-09-20 17:08:45 +000021#include <llvm/Support/Regex.h>
Philip Pfaffe730f2f92017-07-10 10:57:55 +000022#include <llvm/Support/SourceMgr.h>
23#include <llvm/Transforms/Scalar/LoopPassManager.h>
24
25using namespace llvm;
26
27namespace llvm {
28/// Provide an ostream operator for StringRef.
29///
30/// For convenience we provide a custom matcher below for IRUnit's and analysis
31/// result's getName functions, which most of the time returns a StringRef. The
32/// matcher makes use of this operator.
33static std::ostream &operator<<(std::ostream &O, StringRef S) {
34 return O << S.str();
35}
36}
37
38namespace {
Fedor Sergeevee8d31c2018-09-20 17:08:45 +000039using testing::AnyNumber;
40using testing::AtLeast;
Philip Pfaffe730f2f92017-07-10 10:57:55 +000041using testing::DoDefault;
Fedor Sergeevee8d31c2018-09-20 17:08:45 +000042using testing::Not;
Philip Pfaffe730f2f92017-07-10 10:57:55 +000043using testing::Return;
44using testing::Expectation;
45using testing::Invoke;
46using testing::WithArgs;
47using testing::_;
48
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000049/// A CRTP base for analysis mock handles
Philip Pfaffe730f2f92017-07-10 10:57:55 +000050///
51/// This class reconciles mocking with the value semantics implementation of the
52/// AnalysisManager. Analysis mock handles should derive from this class and
53/// call \c setDefault() in their constroctur for wiring up the defaults defined
54/// by this base with their mock run() and invalidate() implementations.
55template <typename DerivedT, typename IRUnitT,
56 typename AnalysisManagerT = AnalysisManager<IRUnitT>,
57 typename... ExtraArgTs>
58class MockAnalysisHandleBase {
59public:
60 class Analysis : public AnalysisInfoMixin<Analysis> {
61 friend AnalysisInfoMixin<Analysis>;
62 friend MockAnalysisHandleBase;
63 static AnalysisKey Key;
64
65 DerivedT *Handle;
66
67 Analysis(DerivedT &Handle) : Handle(&Handle) {
68 static_assert(std::is_base_of<MockAnalysisHandleBase, DerivedT>::value,
69 "Must pass the derived type to this template!");
70 }
71
72 public:
73 class Result {
74 friend MockAnalysisHandleBase;
75
76 DerivedT *Handle;
77
78 Result(DerivedT &Handle) : Handle(&Handle) {}
79
80 public:
81 // Forward invalidation events to the mock handle.
82 bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA,
83 typename AnalysisManagerT::Invalidator &Inv) {
84 return Handle->invalidate(IR, PA, Inv);
85 }
86 };
87
88 Result run(IRUnitT &IR, AnalysisManagerT &AM, ExtraArgTs... ExtraArgs) {
89 return Handle->run(IR, AM, ExtraArgs...);
90 }
91 };
92
93 Analysis getAnalysis() { return Analysis(static_cast<DerivedT &>(*this)); }
94 typename Analysis::Result getResult() {
95 return typename Analysis::Result(static_cast<DerivedT &>(*this));
96 }
Fedor Sergeevee8d31c2018-09-20 17:08:45 +000097 static StringRef getName() { return llvm::getTypeName<DerivedT>(); }
Philip Pfaffe730f2f92017-07-10 10:57:55 +000098
99protected:
100 // FIXME: MSVC seems unable to handle a lambda argument to Invoke from within
101 // the template, so we use a boring static function.
102 static bool invalidateCallback(IRUnitT &IR, const PreservedAnalyses &PA,
103 typename AnalysisManagerT::Invalidator &Inv) {
104 auto PAC = PA.template getChecker<Analysis>();
105 return !PAC.preserved() &&
106 !PAC.template preservedSet<AllAnalysesOn<IRUnitT>>();
107 }
108
109 /// Derived classes should call this in their constructor to set up default
110 /// mock actions. (We can't do this in our constructor because this has to
111 /// run after the DerivedT is constructed.)
112 void setDefaults() {
113 ON_CALL(static_cast<DerivedT &>(*this),
114 run(_, _, testing::Matcher<ExtraArgTs>(_)...))
115 .WillByDefault(Return(this->getResult()));
116 ON_CALL(static_cast<DerivedT &>(*this), invalidate(_, _, _))
117 .WillByDefault(Invoke(&invalidateCallback));
118 }
119};
120
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000121/// A CRTP base for pass mock handles
Philip Pfaffe730f2f92017-07-10 10:57:55 +0000122///
123/// This class reconciles mocking with the value semantics implementation of the
124/// PassManager. Pass mock handles should derive from this class and
125/// call \c setDefault() in their constroctur for wiring up the defaults defined
126/// by this base with their mock run() and invalidate() implementations.
127template <typename DerivedT, typename IRUnitT, typename AnalysisManagerT,
128 typename... ExtraArgTs>
129AnalysisKey MockAnalysisHandleBase<DerivedT, IRUnitT, AnalysisManagerT,
130 ExtraArgTs...>::Analysis::Key;
131
132template <typename DerivedT, typename IRUnitT,
133 typename AnalysisManagerT = AnalysisManager<IRUnitT>,
134 typename... ExtraArgTs>
135class MockPassHandleBase {
136public:
137 class Pass : public PassInfoMixin<Pass> {
138 friend MockPassHandleBase;
139
140 DerivedT *Handle;
141
142 Pass(DerivedT &Handle) : Handle(&Handle) {
143 static_assert(std::is_base_of<MockPassHandleBase, DerivedT>::value,
144 "Must pass the derived type to this template!");
145 }
146
147 public:
148 PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM,
149 ExtraArgTs... ExtraArgs) {
150 return Handle->run(IR, AM, ExtraArgs...);
151 }
152 };
153
Fedor Sergeevee8d31c2018-09-20 17:08:45 +0000154 static StringRef getName() { return llvm::getTypeName<DerivedT>(); }
155
Philip Pfaffe730f2f92017-07-10 10:57:55 +0000156 Pass getPass() { return Pass(static_cast<DerivedT &>(*this)); }
157
158protected:
159 /// Derived classes should call this in their constructor to set up default
160 /// mock actions. (We can't do this in our constructor because this has to
161 /// run after the DerivedT is constructed.)
162 void setDefaults() {
163 ON_CALL(static_cast<DerivedT &>(*this),
164 run(_, _, testing::Matcher<ExtraArgTs>(_)...))
165 .WillByDefault(Return(PreservedAnalyses::all()));
166 }
167};
168
169/// Mock handles for passes for the IRUnits Module, CGSCC, Function, Loop.
170/// These handles define the appropriate run() mock interface for the respective
171/// IRUnit type.
172template <typename IRUnitT> struct MockPassHandle;
173template <>
174struct MockPassHandle<Loop>
175 : MockPassHandleBase<MockPassHandle<Loop>, Loop, LoopAnalysisManager,
176 LoopStandardAnalysisResults &, LPMUpdater &> {
177 MOCK_METHOD4(run,
178 PreservedAnalyses(Loop &, LoopAnalysisManager &,
179 LoopStandardAnalysisResults &, LPMUpdater &));
180 MockPassHandle() { setDefaults(); }
181};
182
183template <>
184struct MockPassHandle<Function>
185 : MockPassHandleBase<MockPassHandle<Function>, Function> {
186 MOCK_METHOD2(run, PreservedAnalyses(Function &, FunctionAnalysisManager &));
187
188 MockPassHandle() { setDefaults(); }
189};
190
191template <>
192struct MockPassHandle<LazyCallGraph::SCC>
193 : MockPassHandleBase<MockPassHandle<LazyCallGraph::SCC>, LazyCallGraph::SCC,
194 CGSCCAnalysisManager, LazyCallGraph &,
195 CGSCCUpdateResult &> {
196 MOCK_METHOD4(run,
197 PreservedAnalyses(LazyCallGraph::SCC &, CGSCCAnalysisManager &,
198 LazyCallGraph &G, CGSCCUpdateResult &UR));
199
200 MockPassHandle() { setDefaults(); }
201};
202
203template <>
204struct MockPassHandle<Module>
205 : MockPassHandleBase<MockPassHandle<Module>, Module> {
206 MOCK_METHOD2(run, PreservedAnalyses(Module &, ModuleAnalysisManager &));
207
208 MockPassHandle() { setDefaults(); }
209};
210
211/// Mock handles for analyses for the IRUnits Module, CGSCC, Function, Loop.
212/// These handles define the appropriate run() and invalidate() mock interfaces
213/// for the respective IRUnit type.
214template <typename IRUnitT> struct MockAnalysisHandle;
215template <>
216struct MockAnalysisHandle<Loop>
217 : MockAnalysisHandleBase<MockAnalysisHandle<Loop>, Loop,
218 LoopAnalysisManager,
219 LoopStandardAnalysisResults &> {
220
221 MOCK_METHOD3_T(run, typename Analysis::Result(Loop &, LoopAnalysisManager &,
222 LoopStandardAnalysisResults &));
223
224 MOCK_METHOD3_T(invalidate, bool(Loop &, const PreservedAnalyses &,
225 LoopAnalysisManager::Invalidator &));
226
227 MockAnalysisHandle<Loop>() { this->setDefaults(); }
228};
229
230template <>
231struct MockAnalysisHandle<Function>
232 : MockAnalysisHandleBase<MockAnalysisHandle<Function>, Function> {
233 MOCK_METHOD2(run, Analysis::Result(Function &, FunctionAnalysisManager &));
234
235 MOCK_METHOD3(invalidate, bool(Function &, const PreservedAnalyses &,
236 FunctionAnalysisManager::Invalidator &));
237
238 MockAnalysisHandle<Function>() { setDefaults(); }
239};
240
241template <>
242struct MockAnalysisHandle<LazyCallGraph::SCC>
243 : MockAnalysisHandleBase<MockAnalysisHandle<LazyCallGraph::SCC>,
244 LazyCallGraph::SCC, CGSCCAnalysisManager,
245 LazyCallGraph &> {
246 MOCK_METHOD3(run, Analysis::Result(LazyCallGraph::SCC &,
247 CGSCCAnalysisManager &, LazyCallGraph &));
248
249 MOCK_METHOD3(invalidate, bool(LazyCallGraph::SCC &, const PreservedAnalyses &,
250 CGSCCAnalysisManager::Invalidator &));
251
252 MockAnalysisHandle<LazyCallGraph::SCC>() { setDefaults(); }
253};
254
255template <>
256struct MockAnalysisHandle<Module>
257 : MockAnalysisHandleBase<MockAnalysisHandle<Module>, Module> {
258 MOCK_METHOD2(run, Analysis::Result(Module &, ModuleAnalysisManager &));
259
260 MOCK_METHOD3(invalidate, bool(Module &, const PreservedAnalyses &,
261 ModuleAnalysisManager::Invalidator &));
262
263 MockAnalysisHandle<Module>() { setDefaults(); }
264};
265
266static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
267 SMDiagnostic Err;
268 return parseAssemblyString(IR, Err, C);
269}
270
Fedor Sergeevee8d31c2018-09-20 17:08:45 +0000271/// Helper for HasName matcher that returns getName both for IRUnit and
272/// for IRUnit pointer wrapper into llvm::Any (wrapped by PassInstrumentation).
273template <typename IRUnitT> std::string getName(const IRUnitT &IR) {
274 return IR.getName();
275}
276
277template <> std::string getName(const StringRef &name) { return name; }
278
279template <> std::string getName(const llvm::Any &WrappedIR) {
280 if (any_isa<const Module *>(WrappedIR))
281 return any_cast<const Module *>(WrappedIR)->getName().str();
282 if (any_isa<const Function *>(WrappedIR))
283 return any_cast<const Function *>(WrappedIR)->getName().str();
284 if (any_isa<const Loop *>(WrappedIR))
285 return any_cast<const Loop *>(WrappedIR)->getName().str();
286 if (any_isa<const LazyCallGraph::SCC *>(WrappedIR))
287 return any_cast<const LazyCallGraph::SCC *>(WrappedIR)->getName();
288 return "<UNKNOWN>";
289}
290/// Define a custom matcher for objects which support a 'getName' method.
291///
292/// LLVM often has IR objects or analysis objects which expose a name
293/// and in tests it is convenient to match these by name for readability.
294/// Usually, this name is either a StringRef or a plain std::string. This
295/// matcher supports any type exposing a getName() method of this form whose
296/// return value is compatible with an std::ostream. For StringRef, this uses
297/// the shift operator defined above.
298///
299/// It should be used as:
300///
301/// HasName("my_function")
302///
303/// No namespace or other qualification is required.
304MATCHER_P(HasName, Name, "") {
305 *result_listener << "has name '" << getName(arg) << "'";
306 return Name == getName(arg);
307}
308
309MATCHER_P(HasNameRegex, Name, "") {
310 *result_listener << "has name '" << getName(arg) << "'";
311 llvm::Regex r(Name);
312 return r.match(getName(arg));
313}
314
315struct MockPassInstrumentationCallbacks {
316 PassInstrumentationCallbacks Callbacks;
317
318 MockPassInstrumentationCallbacks() {
319 ON_CALL(*this, runBeforePass(_, _)).WillByDefault(Return(true));
320 }
321 MOCK_METHOD2(runBeforePass, bool(StringRef PassID, llvm::Any));
322 MOCK_METHOD2(runAfterPass, void(StringRef PassID, llvm::Any));
323
324 void registerPassInstrumentation() {
325 Callbacks.registerBeforePassCallback([this](StringRef P, llvm::Any IR) {
326 return this->runBeforePass(P, IR);
327 });
328 Callbacks.registerAfterPassCallback(
329 [this](StringRef P, llvm::Any IR) { this->runAfterPass(P, IR); });
330 }
331
332 void ignoreNonMockPassInstrumentation(StringRef IRName) {
333 // Generic EXPECT_CALLs are needed to match instrumentation on unimportant
334 // parts of a pipeline that we do not care about (e.g. various passes added
335 // by default by PassBuilder - Verifier pass etc).
336 // Make sure to avoid ignoring Mock passes/analysis, we definitely want
337 // to check these explicitly.
338 EXPECT_CALL(*this,
339 runBeforePass(Not(HasNameRegex("Mock")), HasName(IRName)))
340 .Times(AnyNumber());
341 EXPECT_CALL(*this, runAfterPass(Not(HasNameRegex("Mock")), HasName(IRName)))
342 .Times(AnyNumber());
343 }
344};
345
Philip Pfaffe730f2f92017-07-10 10:57:55 +0000346template <typename PassManagerT> class PassBuilderCallbacksTest;
347
348/// This test fixture is shared between all the actual tests below and
349/// takes care of setting up appropriate defaults.
350///
351/// The template specialization serves to extract the IRUnit and AM types from
352/// the given PassManagerT.
353template <typename TestIRUnitT, typename... ExtraPassArgTs,
354 typename... ExtraAnalysisArgTs>
355class PassBuilderCallbacksTest<PassManager<
356 TestIRUnitT, AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>,
357 ExtraPassArgTs...>> : public testing::Test {
358protected:
359 using IRUnitT = TestIRUnitT;
360 using AnalysisManagerT = AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>;
361 using PassManagerT =
362 PassManager<TestIRUnitT, AnalysisManagerT, ExtraPassArgTs...>;
363 using AnalysisT = typename MockAnalysisHandle<IRUnitT>::Analysis;
364
365 LLVMContext Context;
366 std::unique_ptr<Module> M;
367
Fedor Sergeevee8d31c2018-09-20 17:08:45 +0000368 MockPassInstrumentationCallbacks CallbacksHandle;
369
Philip Pfaffe730f2f92017-07-10 10:57:55 +0000370 PassBuilder PB;
371 ModulePassManager PM;
372 LoopAnalysisManager LAM;
373 FunctionAnalysisManager FAM;
374 CGSCCAnalysisManager CGAM;
375 ModuleAnalysisManager AM;
376
377 MockPassHandle<IRUnitT> PassHandle;
378 MockAnalysisHandle<IRUnitT> AnalysisHandle;
379
380 static PreservedAnalyses getAnalysisResult(IRUnitT &U, AnalysisManagerT &AM,
381 ExtraAnalysisArgTs &&... Args) {
382 (void)AM.template getResult<AnalysisT>(
383 U, std::forward<ExtraAnalysisArgTs>(Args)...);
384 return PreservedAnalyses::all();
385 }
386
387 PassBuilderCallbacksTest()
388 : M(parseIR(Context,
389 "declare void @bar()\n"
390 "define void @foo(i32 %n) {\n"
391 "entry:\n"
392 " br label %loop\n"
393 "loop:\n"
394 " %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]\n"
395 " %iv.next = add i32 %iv, 1\n"
396 " tail call void @bar()\n"
397 " %cmp = icmp eq i32 %iv, %n\n"
398 " br i1 %cmp, label %exit, label %loop\n"
399 "exit:\n"
400 " ret void\n"
401 "}\n")),
Fedor Sergeevee8d31c2018-09-20 17:08:45 +0000402 CallbacksHandle(), PB(nullptr, None, &CallbacksHandle.Callbacks),
Philip Pfaffe730f2f92017-07-10 10:57:55 +0000403 PM(true), LAM(true), FAM(true), CGAM(true), AM(true) {
404
405 /// Register a callback for analysis registration.
406 ///
407 /// The callback is a function taking a reference to an AnalyisManager
408 /// object. When called, the callee gets to register its own analyses with
409 /// this PassBuilder instance.
410 PB.registerAnalysisRegistrationCallback([this](AnalysisManagerT &AM) {
411 // Register our mock analysis
412 AM.registerPass([this] { return AnalysisHandle.getAnalysis(); });
413 });
414
415 /// Register a callback for pipeline parsing.
416 ///
417 /// During parsing of a textual pipeline, the PassBuilder will call these
418 /// callbacks for each encountered pass name that it does not know. This
419 /// includes both simple pass names as well as names of sub-pipelines. In
420 /// the latter case, the InnerPipeline is not empty.
421 PB.registerPipelineParsingCallback(
422 [this](StringRef Name, PassManagerT &PM,
423 ArrayRef<PassBuilder::PipelineElement> InnerPipeline) {
424 /// Handle parsing of the names of analysis utilities such as
425 /// require<test-analysis> and invalidate<test-analysis> for our
426 /// analysis mock handle
427 if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis", Name, PM))
428 return true;
429
430 /// Parse the name of our pass mock handle
431 if (Name == "test-transform") {
432 PM.addPass(PassHandle.getPass());
433 return true;
434 }
435 return false;
436 });
437
438 /// Register builtin analyses and cross-register the analysis proxies
439 PB.registerModuleAnalyses(AM);
440 PB.registerCGSCCAnalyses(CGAM);
441 PB.registerFunctionAnalyses(FAM);
442 PB.registerLoopAnalyses(LAM);
443 PB.crossRegisterProxies(LAM, FAM, CGAM, AM);
444 }
445};
446
Philip Pfaffe730f2f92017-07-10 10:57:55 +0000447using ModuleCallbacksTest = PassBuilderCallbacksTest<ModulePassManager>;
448using CGSCCCallbacksTest = PassBuilderCallbacksTest<CGSCCPassManager>;
449using FunctionCallbacksTest = PassBuilderCallbacksTest<FunctionPassManager>;
450using LoopCallbacksTest = PassBuilderCallbacksTest<LoopPassManager>;
451
452/// Test parsing of the name of our mock pass for all IRUnits.
453///
454/// The pass should by default run our mock analysis and then preserve it.
455TEST_F(ModuleCallbacksTest, Passes) {
456 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
457 EXPECT_CALL(PassHandle, run(HasName("<string>"), _))
458 .WillOnce(Invoke(getAnalysisResult));
459
460 StringRef PipelineText = "test-transform";
461 ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
462 << "Pipeline was: " << PipelineText;
Fedor Sergeevee8d31c2018-09-20 17:08:45 +0000463
464 PM.run(*M, AM);
465}
466
467TEST_F(ModuleCallbacksTest, InstrumentedPasses) {
468 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
469 EXPECT_CALL(PassHandle, run(HasName("<string>"), _))
470 .WillOnce(Invoke(getAnalysisResult));
471
472 CallbacksHandle.registerPassInstrumentation();
473 // Non-mock instrumentation not specifically mentioned below can be ignored.
474 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
475
476 // PassInstrumentation calls should happen in-sequence, in the same order
477 // as passes/analyses are scheduled.
478 ::testing::Sequence PISequence;
479 EXPECT_CALL(CallbacksHandle, runBeforePass(HasNameRegex("MockPassHandle"),
480 HasName("<string>")))
481 .InSequence(PISequence);
482 EXPECT_CALL(CallbacksHandle,
483 runAfterPass(HasNameRegex("MockPassHandle"), HasName("<string>")))
484 .InSequence(PISequence);
485
486 StringRef PipelineText = "test-transform";
487 ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
488 << "Pipeline was: " << PipelineText;
489
490 PM.run(*M, AM);
491}
492
493TEST_F(ModuleCallbacksTest, InstrumentedSkippedPasses) {
494 CallbacksHandle.registerPassInstrumentation();
495 // Non-mock instrumentation run here can safely be ignored.
496 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
497
498 // Skip the pass by returning false.
499 EXPECT_CALL(CallbacksHandle, runBeforePass(HasNameRegex("MockPassHandle"),
500 HasName("<string>")))
501 .WillOnce(Return(false));
502
503 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)).Times(0);
504 EXPECT_CALL(PassHandle, run(HasName("<string>"), _)).Times(0);
505
506 // As the pass is skipped there is no afterPass as well.
507 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _))
508 .Times(0);
509
510 StringRef PipelineText = "test-transform";
511 ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
512 << "Pipeline was: " << PipelineText;
513
Philip Pfaffe730f2f92017-07-10 10:57:55 +0000514 PM.run(*M, AM);
515}
516
517TEST_F(FunctionCallbacksTest, Passes) {
518 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));
519 EXPECT_CALL(PassHandle, run(HasName("foo"), _))
520 .WillOnce(Invoke(getAnalysisResult));
521
522 StringRef PipelineText = "test-transform";
523 ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
524 << "Pipeline was: " << PipelineText;
525 PM.run(*M, AM);
526}
527
Fedor Sergeevee8d31c2018-09-20 17:08:45 +0000528TEST_F(FunctionCallbacksTest, InstrumentedPasses) {
529 CallbacksHandle.registerPassInstrumentation();
530 // Non-mock instrumentation not specifically mentioned below can be ignored.
531 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
532 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
533
534 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));
535 EXPECT_CALL(PassHandle, run(HasName("foo"), _))
536 .WillOnce(Invoke(getAnalysisResult));
537
538 // PassInstrumentation calls should happen in-sequence, in the same order
539 // as passes/analyses are scheduled.
540 ::testing::Sequence PISequence;
541 EXPECT_CALL(CallbacksHandle,
542 runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo")))
543 .InSequence(PISequence);
544 EXPECT_CALL(CallbacksHandle,
545 runAfterPass(HasNameRegex("MockPassHandle"), HasName("foo")))
546 .InSequence(PISequence);
547
548 StringRef PipelineText = "test-transform";
549 ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
550 << "Pipeline was: " << PipelineText;
551 PM.run(*M, AM);
552}
553
554TEST_F(FunctionCallbacksTest, InstrumentedSkippedPasses) {
555 CallbacksHandle.registerPassInstrumentation();
556 // Non-mock instrumentation run here can safely be ignored.
557 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
558 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
559
560 // Skip the pass by returning false.
561 EXPECT_CALL(CallbacksHandle,
562 runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo")))
563 .WillOnce(Return(false));
564
565 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _)).Times(0);
566 EXPECT_CALL(PassHandle, run(HasName("foo"), _)).Times(0);
567
568 // As the pass is skipped there is no afterPass as well.
569 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _))
570 .Times(0);
571
572 StringRef PipelineText = "test-transform";
573 ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
574 << "Pipeline was: " << PipelineText;
575 PM.run(*M, AM);
576}
577
Philip Pfaffe730f2f92017-07-10 10:57:55 +0000578TEST_F(LoopCallbacksTest, Passes) {
579 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
580 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))
581 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
582
583 StringRef PipelineText = "test-transform";
584 ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
585 << "Pipeline was: " << PipelineText;
586 PM.run(*M, AM);
587}
588
Fedor Sergeevee8d31c2018-09-20 17:08:45 +0000589TEST_F(LoopCallbacksTest, InstrumentedPasses) {
590 CallbacksHandle.registerPassInstrumentation();
591 // Non-mock instrumentation not specifically mentioned below can be ignored.
592 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
593 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
594 CallbacksHandle.ignoreNonMockPassInstrumentation("loop");
595
596 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
597 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))
598 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
599
600 // PassInstrumentation calls should happen in-sequence, in the same order
601 // as passes/analyses are scheduled.
602 ::testing::Sequence PISequence;
603 EXPECT_CALL(CallbacksHandle,
604 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
605 .InSequence(PISequence);
606 EXPECT_CALL(CallbacksHandle,
607 runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop")))
608 .InSequence(PISequence);
609
610 StringRef PipelineText = "test-transform";
611 ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
612 << "Pipeline was: " << PipelineText;
613 PM.run(*M, AM);
614}
615
616TEST_F(LoopCallbacksTest, InstrumentedSkippedPasses) {
617 CallbacksHandle.registerPassInstrumentation();
618 // Non-mock instrumentation run here can safely be ignored.
619 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
620 CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
621 CallbacksHandle.ignoreNonMockPassInstrumentation("loop");
622
623 // Skip the pass by returning false.
624 EXPECT_CALL(CallbacksHandle,
625 runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
626 .WillOnce(Return(false));
627
628 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)).Times(0);
629 EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _)).Times(0);
630
631 // As the pass is skipped there is no afterPass as well.
632 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _))
633 .Times(0);
634
635 StringRef PipelineText = "test-transform";
636 ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
637 << "Pipeline was: " << PipelineText;
638 PM.run(*M, AM);
639}
640
Philip Pfaffe730f2f92017-07-10 10:57:55 +0000641TEST_F(CGSCCCallbacksTest, Passes) {
642 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
643 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _))
644 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
645
646 StringRef PipelineText = "test-transform";
647 ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
648 << "Pipeline was: " << PipelineText;
649 PM.run(*M, AM);
650}
651
Fedor Sergeevee8d31c2018-09-20 17:08:45 +0000652TEST_F(CGSCCCallbacksTest, InstrumentedPasses) {
653 CallbacksHandle.registerPassInstrumentation();
654 // Non-mock instrumentation not specifically mentioned below can be ignored.
655 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
656 CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)");
657
658 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
659 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _))
660 .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
661
662 // PassInstrumentation calls should happen in-sequence, in the same order
663 // as passes/analyses are scheduled.
664 ::testing::Sequence PISequence;
665 EXPECT_CALL(CallbacksHandle,
666 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
667 .InSequence(PISequence);
668 EXPECT_CALL(CallbacksHandle,
669 runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
670 .InSequence(PISequence);
671
672 StringRef PipelineText = "test-transform";
673 ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
674 << "Pipeline was: " << PipelineText;
675 PM.run(*M, AM);
676}
677
678TEST_F(CGSCCCallbacksTest, InstrumentedSkippedPasses) {
679 CallbacksHandle.registerPassInstrumentation();
680 // Non-mock instrumentation run here can safely be ignored.
681 CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
682 CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)");
683
684 // Skip the pass by returning false.
685 EXPECT_CALL(CallbacksHandle,
686 runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
687 .WillOnce(Return(false));
688
689 // neither Analysis nor Pass are called.
690 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)).Times(0);
691 EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _)).Times(0);
692
693 // As the pass is skipped there is no afterPass as well.
694 EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"), _))
695 .Times(0);
696
697 StringRef PipelineText = "test-transform";
698 ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
699 << "Pipeline was: " << PipelineText;
700 PM.run(*M, AM);
701}
702
Philip Pfaffe730f2f92017-07-10 10:57:55 +0000703/// Test parsing of the names of analysis utilities for our mock analysis
704/// for all IRUnits.
705///
706/// We first require<>, then invalidate<> it, expecting the analysis to be run
707/// once and subsequently invalidated.
708TEST_F(ModuleCallbacksTest, AnalysisUtilities) {
709 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
710 EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _));
711
712 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
713 ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
714 << "Pipeline was: " << PipelineText;
715 PM.run(*M, AM);
716}
717
718TEST_F(CGSCCCallbacksTest, PassUtilities) {
719 EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
720 EXPECT_CALL(AnalysisHandle, invalidate(HasName("(foo)"), _, _));
721
722 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
723 ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
724 << "Pipeline was: " << PipelineText;
725 PM.run(*M, AM);
726}
727
728TEST_F(FunctionCallbacksTest, AnalysisUtilities) {
729 EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));
730 EXPECT_CALL(AnalysisHandle, invalidate(HasName("foo"), _, _));
731
732 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
733 ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
734 << "Pipeline was: " << PipelineText;
735 PM.run(*M, AM);
736}
737
738TEST_F(LoopCallbacksTest, PassUtilities) {
739 EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
740 EXPECT_CALL(AnalysisHandle, invalidate(HasName("loop"), _, _));
741
742 StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
743
744 ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
745 << "Pipeline was: " << PipelineText;
746 PM.run(*M, AM);
747}
748
749/// Test parsing of the top-level pipeline.
750///
751/// The ParseTopLevelPipeline callback takes over parsing of the entire pipeline
752/// from PassBuilder if it encounters an unknown pipeline entry at the top level
753/// (i.e., the first entry on the pipeline).
754/// This test parses a pipeline named 'another-pipeline', whose only elements
755/// may be the test-transform pass or the analysis utilities
756TEST_F(ModuleCallbacksTest, ParseTopLevelPipeline) {
757 PB.registerParseTopLevelPipelineCallback([this](
758 ModulePassManager &MPM, ArrayRef<PassBuilder::PipelineElement> Pipeline,
759 bool VerifyEachPass, bool DebugLogging) {
760 auto &FirstName = Pipeline.front().Name;
761 auto &InnerPipeline = Pipeline.front().InnerPipeline;
762 if (FirstName == "another-pipeline") {
763 for (auto &E : InnerPipeline) {
764 if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis", E.Name, PM))
765 continue;
766
767 if (E.Name == "test-transform") {
768 PM.addPass(PassHandle.getPass());
769 continue;
770 }
771 return false;
772 }
773 }
774 return true;
775 });
776
777 EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
778 EXPECT_CALL(PassHandle, run(HasName("<string>"), _))
779 .WillOnce(Invoke(getAnalysisResult));
780 EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _));
781
782 StringRef PipelineText =
783 "another-pipeline(test-transform,invalidate<test-analysis>)";
784 ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
785 << "Pipeline was: " << PipelineText;
786 PM.run(*M, AM);
787
788 /// Test the negative case
789 PipelineText = "another-pipeline(instcombine)";
790 ASSERT_FALSE(PB.parsePassPipeline(PM, PipelineText, true))
791 << "Pipeline was: " << PipelineText;
792}
793} // end anonymous namespace