xref: /llvm-project/llvm/unittests/Analysis/CtxProfAnalysisTest.cpp (revision 82266d3a2b33f49165c0f24d3db5ea9875cc706c)
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