1c8a678b1SMircea Trofin //===--- CtxProfAnalysisTest.cpp ------------------------------------------===// 2c8a678b1SMircea Trofin // 3c8a678b1SMircea Trofin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4c8a678b1SMircea Trofin // See https://llvm.org/LICENSE.txt for license information. 5c8a678b1SMircea Trofin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6c8a678b1SMircea Trofin // 7c8a678b1SMircea Trofin //===----------------------------------------------------------------------===// 8c8a678b1SMircea Trofin 9c8a678b1SMircea Trofin #include "llvm/Analysis/CtxProfAnalysis.h" 10c8a678b1SMircea Trofin #include "llvm/Analysis/BlockFrequencyInfo.h" 11c8a678b1SMircea Trofin #include "llvm/Analysis/BranchProbabilityInfo.h" 12c8a678b1SMircea Trofin #include "llvm/Analysis/CGSCCPassManager.h" 13c8a678b1SMircea Trofin #include "llvm/Analysis/LoopAnalysisManager.h" 14c8a678b1SMircea Trofin #include "llvm/AsmParser/Parser.h" 15c8a678b1SMircea Trofin #include "llvm/IR/Analysis.h" 16c8a678b1SMircea Trofin #include "llvm/IR/Module.h" 17c8a678b1SMircea Trofin #include "llvm/IR/PassInstrumentation.h" 18c8a678b1SMircea Trofin #include "llvm/IR/PassManager.h" 19c8a678b1SMircea Trofin #include "llvm/Passes/PassBuilder.h" 20c8a678b1SMircea Trofin #include "llvm/Support/SourceMgr.h" 21c8a678b1SMircea Trofin #include "llvm/Transforms/Instrumentation/PGOInstrumentation.h" 22c8a678b1SMircea Trofin #include "gmock/gmock.h" 23c8a678b1SMircea Trofin #include "gtest/gtest.h" 24c8a678b1SMircea Trofin 25c8a678b1SMircea Trofin using namespace llvm; 26c8a678b1SMircea Trofin 27c8a678b1SMircea Trofin namespace { 28c8a678b1SMircea Trofin 29c8a678b1SMircea Trofin class CtxProfAnalysisTest : public testing::Test { 30c8a678b1SMircea Trofin static constexpr auto *IR = R"IR( 31c8a678b1SMircea Trofin declare void @bar() 32c8a678b1SMircea Trofin 33c8a678b1SMircea Trofin define private void @foo(i32 %a, ptr %fct) #0 !guid !0 { 34c8a678b1SMircea Trofin %t = icmp eq i32 %a, 0 35c8a678b1SMircea Trofin br i1 %t, label %yes, label %no 36c8a678b1SMircea Trofin yes: 37c8a678b1SMircea Trofin call void %fct(i32 %a) 38c8a678b1SMircea Trofin br label %exit 39c8a678b1SMircea Trofin no: 40c8a678b1SMircea Trofin call void @bar() 41c8a678b1SMircea Trofin br label %exit 42c8a678b1SMircea Trofin exit: 43c8a678b1SMircea Trofin ret void 44c8a678b1SMircea Trofin } 45c8a678b1SMircea Trofin 46c8a678b1SMircea Trofin define void @an_entrypoint(i32 %a) { 47c8a678b1SMircea Trofin %t = icmp eq i32 %a, 0 48c8a678b1SMircea Trofin br i1 %t, label %yes, label %no 49c8a678b1SMircea Trofin 50c8a678b1SMircea Trofin yes: 51c8a678b1SMircea Trofin call void @foo(i32 1, ptr null) 52c8a678b1SMircea Trofin ret void 53c8a678b1SMircea Trofin no: 54c8a678b1SMircea Trofin ret void 55c8a678b1SMircea Trofin } 56c8a678b1SMircea Trofin 57c8a678b1SMircea Trofin define void @another_entrypoint_no_callees(i32 %a) { 58c8a678b1SMircea Trofin %t = icmp eq i32 %a, 0 59c8a678b1SMircea Trofin br i1 %t, label %yes, label %no 60c8a678b1SMircea Trofin 61c8a678b1SMircea Trofin yes: 62c8a678b1SMircea Trofin ret void 63c8a678b1SMircea Trofin no: 64c8a678b1SMircea Trofin ret void 65c8a678b1SMircea Trofin } 66c8a678b1SMircea Trofin 67*82266d3aSMircea Trofin define void @inlineasm() { 68*82266d3aSMircea Trofin call void asm "nop", ""() 69*82266d3aSMircea Trofin ret void 70*82266d3aSMircea Trofin } 71*82266d3aSMircea Trofin 72c8a678b1SMircea Trofin attributes #0 = { noinline } 73c8a678b1SMircea Trofin !0 = !{ i64 11872291593386833696 } 74c8a678b1SMircea Trofin )IR"; 75c8a678b1SMircea Trofin 76c8a678b1SMircea Trofin protected: 77c8a678b1SMircea Trofin LLVMContext C; 78c8a678b1SMircea Trofin PassBuilder PB; 79c8a678b1SMircea Trofin ModuleAnalysisManager MAM; 80c8a678b1SMircea Trofin FunctionAnalysisManager FAM; 81c8a678b1SMircea Trofin CGSCCAnalysisManager CGAM; 82c8a678b1SMircea Trofin LoopAnalysisManager LAM; 83c8a678b1SMircea Trofin std::unique_ptr<Module> M; 84c8a678b1SMircea Trofin 85c8a678b1SMircea Trofin void SetUp() override { 86c8a678b1SMircea Trofin SMDiagnostic Err; 87c8a678b1SMircea Trofin M = parseAssemblyString(IR, Err, C); 88c8a678b1SMircea Trofin ASSERT_TRUE(!!M); 89c8a678b1SMircea Trofin } 90c8a678b1SMircea Trofin 91c8a678b1SMircea Trofin public: 92c8a678b1SMircea Trofin CtxProfAnalysisTest() { 93c8a678b1SMircea Trofin PB.registerModuleAnalyses(MAM); 94c8a678b1SMircea Trofin PB.registerCGSCCAnalyses(CGAM); 95c8a678b1SMircea Trofin PB.registerFunctionAnalyses(FAM); 96c8a678b1SMircea Trofin PB.registerLoopAnalyses(LAM); 97c8a678b1SMircea Trofin PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); 98c8a678b1SMircea Trofin } 99c8a678b1SMircea Trofin }; 100c8a678b1SMircea Trofin 101c8a678b1SMircea Trofin TEST_F(CtxProfAnalysisTest, GetCallsiteIDTest) { 102c8a678b1SMircea Trofin ModulePassManager MPM; 103c8a678b1SMircea Trofin MPM.addPass(PGOInstrumentationGen(PGOInstrumentationType::CTXPROF)); 104c8a678b1SMircea Trofin EXPECT_FALSE(MPM.run(*M, MAM).areAllPreserved()); 105c8a678b1SMircea Trofin auto *F = M->getFunction("foo"); 106c8a678b1SMircea Trofin ASSERT_NE(F, nullptr); 107c8a678b1SMircea Trofin std::vector<uint32_t> InsValues; 108c8a678b1SMircea Trofin 109c8a678b1SMircea Trofin for (auto &BB : *F) 110c8a678b1SMircea Trofin for (auto &I : BB) 111c8a678b1SMircea Trofin if (auto *CB = dyn_cast<CallBase>(&I)) { 112c8a678b1SMircea Trofin // Skip instrumentation inserted intrinsics. 113c8a678b1SMircea Trofin if (CB->getCalledFunction() && CB->getCalledFunction()->isIntrinsic()) 114c8a678b1SMircea Trofin continue; 115c8a678b1SMircea Trofin auto *Ins = CtxProfAnalysis::getCallsiteInstrumentation(*CB); 116c8a678b1SMircea Trofin ASSERT_NE(Ins, nullptr); 117c8a678b1SMircea Trofin InsValues.push_back(Ins->getIndex()->getZExtValue()); 118c8a678b1SMircea Trofin } 119c8a678b1SMircea Trofin 120c8a678b1SMircea Trofin EXPECT_THAT(InsValues, testing::ElementsAre(0, 1)); 121c8a678b1SMircea Trofin } 122c8a678b1SMircea Trofin 123*82266d3aSMircea Trofin TEST_F(CtxProfAnalysisTest, GetCallsiteIDInlineAsmTest) { 124*82266d3aSMircea Trofin ModulePassManager MPM; 125*82266d3aSMircea Trofin MPM.addPass(PGOInstrumentationGen(PGOInstrumentationType::CTXPROF)); 126*82266d3aSMircea Trofin EXPECT_FALSE(MPM.run(*M, MAM).areAllPreserved()); 127*82266d3aSMircea Trofin auto *F = M->getFunction("inlineasm"); 128*82266d3aSMircea Trofin ASSERT_NE(F, nullptr); 129*82266d3aSMircea Trofin std::vector<const Instruction *> InsValues; 130*82266d3aSMircea Trofin 131*82266d3aSMircea Trofin for (auto &BB : *F) 132*82266d3aSMircea Trofin for (auto &I : BB) 133*82266d3aSMircea Trofin if (auto *CB = dyn_cast<CallBase>(&I)) { 134*82266d3aSMircea Trofin // Skip instrumentation inserted intrinsics. 135*82266d3aSMircea Trofin if (CB->getCalledFunction() && CB->getCalledFunction()->isIntrinsic()) 136*82266d3aSMircea Trofin continue; 137*82266d3aSMircea Trofin auto *Ins = CtxProfAnalysis::getCallsiteInstrumentation(*CB); 138*82266d3aSMircea Trofin InsValues.push_back(Ins); 139*82266d3aSMircea Trofin } 140*82266d3aSMircea Trofin 141*82266d3aSMircea Trofin EXPECT_THAT(InsValues, testing::ElementsAre(nullptr)); 142*82266d3aSMircea Trofin } 143*82266d3aSMircea Trofin 144c8a678b1SMircea Trofin TEST_F(CtxProfAnalysisTest, GetCallsiteIDNegativeTest) { 145c8a678b1SMircea Trofin auto *F = M->getFunction("foo"); 146c8a678b1SMircea Trofin ASSERT_NE(F, nullptr); 147c8a678b1SMircea Trofin CallBase *FirstCall = nullptr; 148c8a678b1SMircea Trofin for (auto &BB : *F) 149c8a678b1SMircea Trofin for (auto &I : BB) 150c8a678b1SMircea Trofin if (auto *CB = dyn_cast<CallBase>(&I)) { 151c8a678b1SMircea Trofin if (CB->isIndirectCall() || !CB->getCalledFunction()->isIntrinsic()) { 152c8a678b1SMircea Trofin FirstCall = CB; 153c8a678b1SMircea Trofin break; 154c8a678b1SMircea Trofin } 155c8a678b1SMircea Trofin } 156c8a678b1SMircea Trofin ASSERT_NE(FirstCall, nullptr); 157c8a678b1SMircea Trofin auto *IndIns = CtxProfAnalysis::getCallsiteInstrumentation(*FirstCall); 158c8a678b1SMircea Trofin EXPECT_EQ(IndIns, nullptr); 159c8a678b1SMircea Trofin } 160c8a678b1SMircea Trofin 1611e70122cSMircea Trofin TEST_F(CtxProfAnalysisTest, GetBBIDTest) { 1621e70122cSMircea Trofin ModulePassManager MPM; 1631e70122cSMircea Trofin MPM.addPass(PGOInstrumentationGen(PGOInstrumentationType::CTXPROF)); 1641e70122cSMircea Trofin EXPECT_FALSE(MPM.run(*M, MAM).areAllPreserved()); 1651e70122cSMircea Trofin auto *F = M->getFunction("foo"); 1661e70122cSMircea Trofin ASSERT_NE(F, nullptr); 1671e70122cSMircea Trofin std::map<std::string, int> BBNameAndID; 1681e70122cSMircea Trofin 1691e70122cSMircea Trofin for (auto &BB : *F) { 1701e70122cSMircea Trofin auto *Ins = CtxProfAnalysis::getBBInstrumentation(BB); 1711e70122cSMircea Trofin if (Ins) 1721e70122cSMircea Trofin BBNameAndID[BB.getName().str()] = 1731e70122cSMircea Trofin static_cast<int>(Ins->getIndex()->getZExtValue()); 1741e70122cSMircea Trofin else 1751e70122cSMircea Trofin BBNameAndID[BB.getName().str()] = -1; 1761e70122cSMircea Trofin } 1771e70122cSMircea Trofin 1781e70122cSMircea Trofin EXPECT_THAT(BBNameAndID, 1791e70122cSMircea Trofin testing::UnorderedElementsAre( 1801e70122cSMircea Trofin testing::Pair("", 0), testing::Pair("yes", 1), 1811e70122cSMircea Trofin testing::Pair("no", -1), testing::Pair("exit", -1))); 1821e70122cSMircea Trofin } 183c8a678b1SMircea Trofin } // namespace 184