184 lines
5.0 KiB
C++
184 lines
5.0 KiB
C++
//===--- CtxProfAnalysisTest.cpp ------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Analysis/CtxProfAnalysis.h"
|
|
#include "llvm/Analysis/BlockFrequencyInfo.h"
|
|
#include "llvm/Analysis/BranchProbabilityInfo.h"
|
|
#include "llvm/Analysis/CGSCCPassManager.h"
|
|
#include "llvm/Analysis/LoopAnalysisManager.h"
|
|
#include "llvm/AsmParser/Parser.h"
|
|
#include "llvm/IR/Analysis.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/IR/PassInstrumentation.h"
|
|
#include "llvm/IR/PassManager.h"
|
|
#include "llvm/Passes/PassBuilder.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
#include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
|
|
class CtxProfAnalysisTest : public testing::Test {
|
|
static constexpr auto *IR = R"IR(
|
|
declare void @bar()
|
|
|
|
define private void @foo(i32 %a, ptr %fct) #0 !guid !0 {
|
|
%t = icmp eq i32 %a, 0
|
|
br i1 %t, label %yes, label %no
|
|
yes:
|
|
call void %fct(i32 %a)
|
|
br label %exit
|
|
no:
|
|
call void @bar()
|
|
br label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @an_entrypoint(i32 %a) {
|
|
%t = icmp eq i32 %a, 0
|
|
br i1 %t, label %yes, label %no
|
|
|
|
yes:
|
|
call void @foo(i32 1, ptr null)
|
|
ret void
|
|
no:
|
|
ret void
|
|
}
|
|
|
|
define void @another_entrypoint_no_callees(i32 %a) {
|
|
%t = icmp eq i32 %a, 0
|
|
br i1 %t, label %yes, label %no
|
|
|
|
yes:
|
|
ret void
|
|
no:
|
|
ret void
|
|
}
|
|
|
|
define void @inlineasm() {
|
|
call void asm "nop", ""()
|
|
ret void
|
|
}
|
|
|
|
attributes #0 = { noinline }
|
|
!0 = !{ i64 11872291593386833696 }
|
|
)IR";
|
|
|
|
protected:
|
|
LLVMContext C;
|
|
PassBuilder PB;
|
|
ModuleAnalysisManager MAM;
|
|
FunctionAnalysisManager FAM;
|
|
CGSCCAnalysisManager CGAM;
|
|
LoopAnalysisManager LAM;
|
|
std::unique_ptr<Module> M;
|
|
|
|
void SetUp() override {
|
|
SMDiagnostic Err;
|
|
M = parseAssemblyString(IR, Err, C);
|
|
ASSERT_TRUE(!!M);
|
|
}
|
|
|
|
public:
|
|
CtxProfAnalysisTest() {
|
|
PB.registerModuleAnalyses(MAM);
|
|
PB.registerCGSCCAnalyses(CGAM);
|
|
PB.registerFunctionAnalyses(FAM);
|
|
PB.registerLoopAnalyses(LAM);
|
|
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
|
|
}
|
|
};
|
|
|
|
TEST_F(CtxProfAnalysisTest, GetCallsiteIDTest) {
|
|
ModulePassManager MPM;
|
|
MPM.addPass(PGOInstrumentationGen(PGOInstrumentationType::CTXPROF));
|
|
EXPECT_FALSE(MPM.run(*M, MAM).areAllPreserved());
|
|
auto *F = M->getFunction("foo");
|
|
ASSERT_NE(F, nullptr);
|
|
std::vector<uint32_t> InsValues;
|
|
|
|
for (auto &BB : *F)
|
|
for (auto &I : BB)
|
|
if (auto *CB = dyn_cast<CallBase>(&I)) {
|
|
// Skip instrumentation inserted intrinsics.
|
|
if (CB->getCalledFunction() && CB->getCalledFunction()->isIntrinsic())
|
|
continue;
|
|
auto *Ins = CtxProfAnalysis::getCallsiteInstrumentation(*CB);
|
|
ASSERT_NE(Ins, nullptr);
|
|
InsValues.push_back(Ins->getIndex()->getZExtValue());
|
|
}
|
|
|
|
EXPECT_THAT(InsValues, testing::ElementsAre(0, 1));
|
|
}
|
|
|
|
TEST_F(CtxProfAnalysisTest, GetCallsiteIDInlineAsmTest) {
|
|
ModulePassManager MPM;
|
|
MPM.addPass(PGOInstrumentationGen(PGOInstrumentationType::CTXPROF));
|
|
EXPECT_FALSE(MPM.run(*M, MAM).areAllPreserved());
|
|
auto *F = M->getFunction("inlineasm");
|
|
ASSERT_NE(F, nullptr);
|
|
std::vector<const Instruction *> InsValues;
|
|
|
|
for (auto &BB : *F)
|
|
for (auto &I : BB)
|
|
if (auto *CB = dyn_cast<CallBase>(&I)) {
|
|
// Skip instrumentation inserted intrinsics.
|
|
if (CB->getCalledFunction() && CB->getCalledFunction()->isIntrinsic())
|
|
continue;
|
|
auto *Ins = CtxProfAnalysis::getCallsiteInstrumentation(*CB);
|
|
InsValues.push_back(Ins);
|
|
}
|
|
|
|
EXPECT_THAT(InsValues, testing::ElementsAre(nullptr));
|
|
}
|
|
|
|
TEST_F(CtxProfAnalysisTest, GetCallsiteIDNegativeTest) {
|
|
auto *F = M->getFunction("foo");
|
|
ASSERT_NE(F, nullptr);
|
|
CallBase *FirstCall = nullptr;
|
|
for (auto &BB : *F)
|
|
for (auto &I : BB)
|
|
if (auto *CB = dyn_cast<CallBase>(&I)) {
|
|
if (CB->isIndirectCall() || !CB->getCalledFunction()->isIntrinsic()) {
|
|
FirstCall = CB;
|
|
break;
|
|
}
|
|
}
|
|
ASSERT_NE(FirstCall, nullptr);
|
|
auto *IndIns = CtxProfAnalysis::getCallsiteInstrumentation(*FirstCall);
|
|
EXPECT_EQ(IndIns, nullptr);
|
|
}
|
|
|
|
TEST_F(CtxProfAnalysisTest, GetBBIDTest) {
|
|
ModulePassManager MPM;
|
|
MPM.addPass(PGOInstrumentationGen(PGOInstrumentationType::CTXPROF));
|
|
EXPECT_FALSE(MPM.run(*M, MAM).areAllPreserved());
|
|
auto *F = M->getFunction("foo");
|
|
ASSERT_NE(F, nullptr);
|
|
std::map<std::string, int> BBNameAndID;
|
|
|
|
for (auto &BB : *F) {
|
|
auto *Ins = CtxProfAnalysis::getBBInstrumentation(BB);
|
|
if (Ins)
|
|
BBNameAndID[BB.getName().str()] =
|
|
static_cast<int>(Ins->getIndex()->getZExtValue());
|
|
else
|
|
BBNameAndID[BB.getName().str()] = -1;
|
|
}
|
|
|
|
EXPECT_THAT(BBNameAndID,
|
|
testing::UnorderedElementsAre(
|
|
testing::Pair("", 0), testing::Pair("yes", 1),
|
|
testing::Pair("no", -1), testing::Pair("exit", -1)));
|
|
}
|
|
} // namespace
|