xref: /llvm-project/llvm/unittests/Transforms/Instrumentation/PGOInstrumentationTest.cpp (revision e36b22f3bf45a23d31b569e53d22b98714cf00e3)
18c33b338SPavel Samolysov //===- PGOInstrumentationTest.cpp - Instrumentation unit tests ------------===//
28c33b338SPavel Samolysov //
38c33b338SPavel Samolysov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
48c33b338SPavel Samolysov // See https://llvm.org/LICENSE.txt for license information.
58c33b338SPavel Samolysov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68c33b338SPavel Samolysov //
78c33b338SPavel Samolysov //===----------------------------------------------------------------------===//
88c33b338SPavel Samolysov 
98c33b338SPavel Samolysov #include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
108c33b338SPavel Samolysov #include "llvm/AsmParser/Parser.h"
118c33b338SPavel Samolysov #include "llvm/IR/Module.h"
128c33b338SPavel Samolysov #include "llvm/Passes/PassBuilder.h"
138c33b338SPavel Samolysov #include "llvm/ProfileData/InstrProf.h"
148c33b338SPavel Samolysov 
158c33b338SPavel Samolysov #include "gmock/gmock.h"
168c33b338SPavel Samolysov #include "gtest/gtest.h"
178c33b338SPavel Samolysov 
188c33b338SPavel Samolysov #include <tuple>
198c33b338SPavel Samolysov 
208c33b338SPavel Samolysov namespace {
218c33b338SPavel Samolysov 
228c33b338SPavel Samolysov using namespace llvm;
238c33b338SPavel Samolysov 
248c33b338SPavel Samolysov using testing::_;
258c33b338SPavel Samolysov using ::testing::DoDefault;
268c33b338SPavel Samolysov using ::testing::Invoke;
278c33b338SPavel Samolysov using ::testing::NotNull;
288c33b338SPavel Samolysov using ::testing::Ref;
298c33b338SPavel Samolysov using ::testing::Return;
308c33b338SPavel Samolysov using ::testing::Sequence;
318c33b338SPavel Samolysov using ::testing::Test;
328c33b338SPavel Samolysov using ::testing::TestParamInfo;
338c33b338SPavel Samolysov using ::testing::Values;
348c33b338SPavel Samolysov using ::testing::WithParamInterface;
358c33b338SPavel Samolysov 
368c33b338SPavel Samolysov template <typename Derived> class MockAnalysisHandleBase {
378c33b338SPavel Samolysov public:
388c33b338SPavel Samolysov   class Analysis : public AnalysisInfoMixin<Analysis> {
398c33b338SPavel Samolysov   public:
408c33b338SPavel Samolysov     class Result {
418c33b338SPavel Samolysov     public:
428c33b338SPavel Samolysov       // Forward invalidation events to the mock handle.
438c33b338SPavel Samolysov       bool invalidate(Module &M, const PreservedAnalyses &PA,
448c33b338SPavel Samolysov                       ModuleAnalysisManager::Invalidator &Inv) {
458c33b338SPavel Samolysov         return Handle->invalidate(M, PA, Inv);
468c33b338SPavel Samolysov       }
478c33b338SPavel Samolysov 
488c33b338SPavel Samolysov     private:
498c33b338SPavel Samolysov       explicit Result(Derived *Handle) : Handle(Handle) {}
508c33b338SPavel Samolysov 
518c33b338SPavel Samolysov       friend MockAnalysisHandleBase;
528c33b338SPavel Samolysov       Derived *Handle;
538c33b338SPavel Samolysov     };
548c33b338SPavel Samolysov 
558c33b338SPavel Samolysov     Result run(Module &M, ModuleAnalysisManager &AM) {
568c33b338SPavel Samolysov       return Handle->run(M, AM);
578c33b338SPavel Samolysov     }
588c33b338SPavel Samolysov 
598c33b338SPavel Samolysov   private:
608c33b338SPavel Samolysov     friend AnalysisInfoMixin<Analysis>;
618c33b338SPavel Samolysov     friend MockAnalysisHandleBase;
628c33b338SPavel Samolysov     static inline AnalysisKey Key;
638c33b338SPavel Samolysov 
648c33b338SPavel Samolysov     Derived *Handle;
658c33b338SPavel Samolysov 
668c33b338SPavel Samolysov     explicit Analysis(Derived *Handle) : Handle(Handle) {}
678c33b338SPavel Samolysov   };
688c33b338SPavel Samolysov 
698c33b338SPavel Samolysov   Analysis getAnalysis() { return Analysis(static_cast<Derived *>(this)); }
708c33b338SPavel Samolysov 
718c33b338SPavel Samolysov   typename Analysis::Result getResult() {
728c33b338SPavel Samolysov     return typename Analysis::Result(static_cast<Derived *>(this));
738c33b338SPavel Samolysov   }
748c33b338SPavel Samolysov 
758c33b338SPavel Samolysov protected:
768c33b338SPavel Samolysov   void setDefaults() {
778c33b338SPavel Samolysov     ON_CALL(static_cast<Derived &>(*this), run(_, _))
788c33b338SPavel Samolysov         .WillByDefault(Return(this->getResult()));
798c33b338SPavel Samolysov     ON_CALL(static_cast<Derived &>(*this), invalidate(_, _, _))
808c33b338SPavel Samolysov         .WillByDefault(Invoke([](Module &M, const PreservedAnalyses &PA,
818c33b338SPavel Samolysov                                  ModuleAnalysisManager::Invalidator &) {
828c33b338SPavel Samolysov           auto PAC = PA.template getChecker<Analysis>();
838c33b338SPavel Samolysov           return !PAC.preserved() &&
848c33b338SPavel Samolysov                  !PAC.template preservedSet<AllAnalysesOn<Module>>();
858c33b338SPavel Samolysov         }));
868c33b338SPavel Samolysov   }
878c33b338SPavel Samolysov 
888c33b338SPavel Samolysov private:
898c33b338SPavel Samolysov   friend Derived;
908c33b338SPavel Samolysov   MockAnalysisHandleBase() = default;
918c33b338SPavel Samolysov };
928c33b338SPavel Samolysov 
938c33b338SPavel Samolysov class MockModuleAnalysisHandle
948c33b338SPavel Samolysov     : public MockAnalysisHandleBase<MockModuleAnalysisHandle> {
958c33b338SPavel Samolysov public:
968c33b338SPavel Samolysov   MockModuleAnalysisHandle() { setDefaults(); }
978c33b338SPavel Samolysov 
988c33b338SPavel Samolysov   MOCK_METHOD(typename Analysis::Result, run,
998c33b338SPavel Samolysov               (Module &, ModuleAnalysisManager &));
1008c33b338SPavel Samolysov 
1018c33b338SPavel Samolysov   MOCK_METHOD(bool, invalidate,
1028c33b338SPavel Samolysov               (Module &, const PreservedAnalyses &,
1038c33b338SPavel Samolysov                ModuleAnalysisManager::Invalidator &));
1048c33b338SPavel Samolysov };
1058c33b338SPavel Samolysov 
106*e36b22f3SHoward Roark struct PGOInstrumentationGenTest
107*e36b22f3SHoward Roark     : public Test,
108*e36b22f3SHoward Roark       WithParamInterface<std::tuple<StringRef, StringRef>> {
1098c33b338SPavel Samolysov   ModulePassManager MPM;
1108c33b338SPavel Samolysov   PassBuilder PB;
1118c33b338SPavel Samolysov   MockModuleAnalysisHandle MMAHandle;
1128c33b338SPavel Samolysov   LoopAnalysisManager LAM;
1138c33b338SPavel Samolysov   FunctionAnalysisManager FAM;
1148c33b338SPavel Samolysov   CGSCCAnalysisManager CGAM;
1158c33b338SPavel Samolysov   ModuleAnalysisManager MAM;
1168c33b338SPavel Samolysov   LLVMContext Context;
1178c33b338SPavel Samolysov   std::unique_ptr<Module> M;
1188c33b338SPavel Samolysov 
1198c33b338SPavel Samolysov   PGOInstrumentationGenTest() {
1208c33b338SPavel Samolysov     MAM.registerPass([&] { return MMAHandle.getAnalysis(); });
1218c33b338SPavel Samolysov     PB.registerModuleAnalyses(MAM);
1228c33b338SPavel Samolysov     PB.registerCGSCCAnalyses(CGAM);
1238c33b338SPavel Samolysov     PB.registerFunctionAnalyses(FAM);
1248c33b338SPavel Samolysov     PB.registerLoopAnalyses(LAM);
1258c33b338SPavel Samolysov     PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
1268c33b338SPavel Samolysov     MPM.addPass(
1278c33b338SPavel Samolysov         RequireAnalysisPass<MockModuleAnalysisHandle::Analysis, Module>());
1288c33b338SPavel Samolysov     MPM.addPass(PGOInstrumentationGen());
1298c33b338SPavel Samolysov   }
1308c33b338SPavel Samolysov 
1318c33b338SPavel Samolysov   void parseAssembly(const StringRef IR) {
1328c33b338SPavel Samolysov     SMDiagnostic Error;
1338c33b338SPavel Samolysov     M = parseAssemblyString(IR, Error, Context);
1348c33b338SPavel Samolysov     std::string ErrMsg;
1358c33b338SPavel Samolysov     raw_string_ostream OS(ErrMsg);
1368c33b338SPavel Samolysov     Error.print("", OS);
1378c33b338SPavel Samolysov 
1388c33b338SPavel Samolysov     // A failure here means that the test itself is buggy.
1398c33b338SPavel Samolysov     if (!M)
14052b48a70SJOE1994       report_fatal_error(ErrMsg.c_str());
1418c33b338SPavel Samolysov   }
1428c33b338SPavel Samolysov };
1438c33b338SPavel Samolysov 
1448c33b338SPavel Samolysov static constexpr StringRef CodeWithFuncDefs = R"(
1458c33b338SPavel Samolysov   define i32 @f(i32 %n) {
1468c33b338SPavel Samolysov   entry:
1478c33b338SPavel Samolysov     ret i32 0
1488c33b338SPavel Samolysov   })";
1498c33b338SPavel Samolysov 
150*e36b22f3SHoward Roark static constexpr StringRef CodeWithFuncDecls = R"(
151*e36b22f3SHoward Roark   declare i32 @f(i32);
152*e36b22f3SHoward Roark )";
1538c33b338SPavel Samolysov 
154*e36b22f3SHoward Roark static constexpr StringRef CodeWithGlobals = R"(
155*e36b22f3SHoward Roark   @foo.table = internal unnamed_addr constant [1 x ptr] [ptr @f]
156*e36b22f3SHoward Roark   declare i32 @f(i32);
157*e36b22f3SHoward Roark )";
158*e36b22f3SHoward Roark 
159*e36b22f3SHoward Roark INSTANTIATE_TEST_SUITE_P(
160*e36b22f3SHoward Roark     PGOInstrumetationGenTestSuite, PGOInstrumentationGenTest,
161*e36b22f3SHoward Roark     Values(std::make_tuple(CodeWithFuncDefs, "instrument_function_defs"),
162*e36b22f3SHoward Roark            std::make_tuple(CodeWithFuncDecls, "instrument_function_decls"),
163*e36b22f3SHoward Roark            std::make_tuple(CodeWithGlobals, "instrument_globals")),
164*e36b22f3SHoward Roark     [](const TestParamInfo<PGOInstrumentationGenTest::ParamType> &Info) {
165*e36b22f3SHoward Roark       return std::get<1>(Info.param).str();
166*e36b22f3SHoward Roark     });
167*e36b22f3SHoward Roark 
168*e36b22f3SHoward Roark TEST_P(PGOInstrumentationGenTest, Instrumented) {
1698c33b338SPavel Samolysov   const StringRef Code = std::get<0>(GetParam());
1708c33b338SPavel Samolysov   parseAssembly(Code);
1718c33b338SPavel Samolysov 
1728c33b338SPavel Samolysov   ASSERT_THAT(M, NotNull());
1738c33b338SPavel Samolysov 
1748c33b338SPavel Samolysov   Sequence PassSequence;
1758c33b338SPavel Samolysov   EXPECT_CALL(MMAHandle, run(Ref(*M), _))
1768c33b338SPavel Samolysov       .InSequence(PassSequence)
1778c33b338SPavel Samolysov       .WillOnce(DoDefault());
1788c33b338SPavel Samolysov   EXPECT_CALL(MMAHandle, invalidate(Ref(*M), _, _))
1798c33b338SPavel Samolysov       .InSequence(PassSequence)
1808c33b338SPavel Samolysov       .WillOnce(DoDefault());
1818c33b338SPavel Samolysov 
1828c33b338SPavel Samolysov   MPM.run(*M, MAM);
1838c33b338SPavel Samolysov 
1848c33b338SPavel Samolysov   const auto *IRInstrVar =
1858c33b338SPavel Samolysov       M->getNamedGlobal(INSTR_PROF_QUOTE(INSTR_PROF_RAW_VERSION_VAR));
186*e36b22f3SHoward Roark   EXPECT_THAT(IRInstrVar, NotNull());
1878c33b338SPavel Samolysov   EXPECT_FALSE(IRInstrVar->isDeclaration());
1888c33b338SPavel Samolysov }
1898c33b338SPavel Samolysov 
1908c33b338SPavel Samolysov } // end anonymous namespace
191