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