blob: aac5ee6b3e53fc866e655e493f86c31551f86e2e [file] [log] [blame]
//===- llvm/unittest/CodeGen/PassManager.cpp - PassManager tests ----------===//
//
// 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/ADT/Triple.h"
#include "llvm/Analysis/CGSCCPassManager.h"
#include "llvm/Analysis/LoopAnalysisManager.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachinePassManager.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"
#include "gtest/gtest.h"
using namespace llvm;
namespace {
class TestFunctionAnalysis : public AnalysisInfoMixin<TestFunctionAnalysis> {
public:
struct Result {
Result(int Count) : InstructionCount(Count) {}
int InstructionCount;
};
/// Run the analysis pass over the function and return a result.
Result run(Function &F, FunctionAnalysisManager &AM) {
int Count = 0;
for (Function::iterator BBI = F.begin(), BBE = F.end(); BBI != BBE; ++BBI)
for (BasicBlock::iterator II = BBI->begin(), IE = BBI->end(); II != IE;
++II)
++Count;
return Result(Count);
}
private:
friend AnalysisInfoMixin<TestFunctionAnalysis>;
static AnalysisKey Key;
};
AnalysisKey TestFunctionAnalysis::Key;
class TestMachineFunctionAnalysis
: public AnalysisInfoMixin<TestMachineFunctionAnalysis> {
public:
struct Result {
Result(int Count) : InstructionCount(Count) {}
int InstructionCount;
};
/// Run the analysis pass over the machine function and return a result.
Result run(MachineFunction &MF, MachineFunctionAnalysisManager::Base &AM) {
auto &MFAM = static_cast<MachineFunctionAnalysisManager &>(AM);
// Query function analysis result.
TestFunctionAnalysis::Result &FAR =
MFAM.getResult<TestFunctionAnalysis>(MF.getFunction());
// + 5
return FAR.InstructionCount;
}
private:
friend AnalysisInfoMixin<TestMachineFunctionAnalysis>;
static AnalysisKey Key;
};
AnalysisKey TestMachineFunctionAnalysis::Key;
const std::string DoInitErrMsg = "doInitialization failed";
const std::string DoFinalErrMsg = "doFinalization failed";
struct TestMachineFunctionPass : public PassInfoMixin<TestMachineFunctionPass> {
TestMachineFunctionPass(int &Count, std::vector<int> &BeforeInitialization,
std::vector<int> &BeforeFinalization,
std::vector<int> &MachineFunctionPassCount)
: Count(Count), BeforeInitialization(BeforeInitialization),
BeforeFinalization(BeforeFinalization),
MachineFunctionPassCount(MachineFunctionPassCount) {}
Error doInitialization(Module &M, MachineFunctionAnalysisManager &MFAM) {
// Force doInitialization fail by starting with big `Count`.
if (Count > 10000)
return make_error<StringError>(DoInitErrMsg, inconvertibleErrorCode());
// + 1
++Count;
BeforeInitialization.push_back(Count);
return Error::success();
}
Error doFinalization(Module &M, MachineFunctionAnalysisManager &MFAM) {
// Force doFinalization fail by starting with big `Count`.
if (Count > 1000)
return make_error<StringError>(DoFinalErrMsg, inconvertibleErrorCode());
// + 1
++Count;
BeforeFinalization.push_back(Count);
return Error::success();
}
PreservedAnalyses run(MachineFunction &MF,
MachineFunctionAnalysisManager &MFAM) {
// Query function analysis result.
TestFunctionAnalysis::Result &FAR =
MFAM.getResult<TestFunctionAnalysis>(MF.getFunction());
// 3 + 1 + 1 = 5
Count += FAR.InstructionCount;
// Query module analysis result.
MachineModuleInfo &MMI =
MFAM.getResult<MachineModuleAnalysis>(*MF.getFunction().getParent());
// 1 + 1 + 1 = 3
Count += (MMI.getModule() == MF.getFunction().getParent());
// Query machine function analysis result.
TestMachineFunctionAnalysis::Result &MFAR =
MFAM.getResult<TestMachineFunctionAnalysis>(MF);
// 3 + 1 + 1 = 5
Count += MFAR.InstructionCount;
MachineFunctionPassCount.push_back(Count);
return PreservedAnalyses::none();
}
int &Count;
std::vector<int> &BeforeInitialization;
std::vector<int> &BeforeFinalization;
std::vector<int> &MachineFunctionPassCount;
};
struct TestMachineModulePass : public PassInfoMixin<TestMachineModulePass> {
TestMachineModulePass(int &Count, std::vector<int> &MachineModulePassCount)
: Count(Count), MachineModulePassCount(MachineModulePassCount) {}
Error run(Module &M, MachineFunctionAnalysisManager &MFAM) {
MachineModuleInfo &MMI = MFAM.getResult<MachineModuleAnalysis>(M);
// + 1
Count += (MMI.getModule() == &M);
MachineModulePassCount.push_back(Count);
return Error::success();
}
PreservedAnalyses run(MachineFunction &MF,
MachineFunctionAnalysisManager &AM) {
llvm_unreachable(
"This should never be reached because this is machine module pass");
}
int &Count;
std::vector<int> &MachineModulePassCount;
};
std::unique_ptr<Module> parseIR(LLVMContext &Context, const char *IR) {
SMDiagnostic Err;
return parseAssemblyString(IR, Err, Context);
}
class PassManagerTest : public ::testing::Test {
protected:
LLVMContext Context;
std::unique_ptr<Module> M;
std::unique_ptr<TargetMachine> TM;
public:
PassManagerTest()
: M(parseIR(Context, "define void @f() {\n"
"entry:\n"
" call void @g()\n"
" call void @h()\n"
" ret void\n"
"}\n"
"define void @g() {\n"
" ret void\n"
"}\n"
"define void @h() {\n"
" ret void\n"
"}\n")) {
// MachineModuleAnalysis needs a TargetMachine instance.
llvm::InitializeAllTargets();
std::string TripleName = Triple::normalize(sys::getDefaultTargetTriple());
std::string Error;
const Target *TheTarget =
TargetRegistry::lookupTarget(TripleName, Error);
if (!TheTarget)
return;
TargetOptions Options;
TM.reset(TheTarget->createTargetMachine(TripleName, "", "",
Options, None));
}
};
TEST_F(PassManagerTest, Basic) {
if (!TM)
return;
LLVMTargetMachine *LLVMTM = static_cast<LLVMTargetMachine *>(TM.get());
M->setDataLayout(TM->createDataLayout());
LoopAnalysisManager LAM(/*DebugLogging=*/true);
FunctionAnalysisManager FAM(/*DebugLogging=*/true);
CGSCCAnalysisManager CGAM(/*DebugLogging=*/true);
ModuleAnalysisManager MAM(/*DebugLogging=*/true);
PassBuilder PB(TM.get());
PB.registerModuleAnalyses(MAM);
PB.registerFunctionAnalyses(FAM);
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
FAM.registerPass([&] { return TestFunctionAnalysis(); });
FAM.registerPass([&] { return PassInstrumentationAnalysis(); });
MAM.registerPass([&] { return MachineModuleAnalysis(LLVMTM); });
MAM.registerPass([&] { return PassInstrumentationAnalysis(); });
MachineFunctionAnalysisManager MFAM;
{
// Test move assignment.
MachineFunctionAnalysisManager NestedMFAM(FAM, MAM,
/*DebugLogging*/ true);
NestedMFAM.registerPass([&] { return PassInstrumentationAnalysis(); });
NestedMFAM.registerPass([&] { return TestMachineFunctionAnalysis(); });
MFAM = std::move(NestedMFAM);
}
int Count = 0;
std::vector<int> BeforeInitialization[2];
std::vector<int> BeforeFinalization[2];
std::vector<int> TestMachineFunctionCount[2];
std::vector<int> TestMachineModuleCount[2];
MachineFunctionPassManager MFPM;
{
// Test move assignment.
MachineFunctionPassManager NestedMFPM(/*DebugLogging*/ true);
NestedMFPM.addPass(TestMachineModulePass(Count, TestMachineModuleCount[0]));
NestedMFPM.addPass(TestMachineFunctionPass(Count, BeforeInitialization[0],
BeforeFinalization[0],
TestMachineFunctionCount[0]));
NestedMFPM.addPass(TestMachineModulePass(Count, TestMachineModuleCount[1]));
NestedMFPM.addPass(TestMachineFunctionPass(Count, BeforeInitialization[1],
BeforeFinalization[1],
TestMachineFunctionCount[1]));
MFPM = std::move(NestedMFPM);
}
ASSERT_FALSE(errorToBool(MFPM.run(*M, MFAM)));
// Check first machine module pass
EXPECT_EQ(1u, TestMachineModuleCount[0].size());
EXPECT_EQ(3, TestMachineModuleCount[0][0]);
// Check first machine function pass
EXPECT_EQ(1u, BeforeInitialization[0].size());
EXPECT_EQ(1, BeforeInitialization[0][0]);
EXPECT_EQ(3u, TestMachineFunctionCount[0].size());
EXPECT_EQ(10, TestMachineFunctionCount[0][0]);
EXPECT_EQ(13, TestMachineFunctionCount[0][1]);
EXPECT_EQ(16, TestMachineFunctionCount[0][2]);
EXPECT_EQ(1u, BeforeFinalization[0].size());
EXPECT_EQ(31, BeforeFinalization[0][0]);
// Check second machine module pass
EXPECT_EQ(1u, TestMachineModuleCount[1].size());
EXPECT_EQ(17, TestMachineModuleCount[1][0]);
// Check second machine function pass
EXPECT_EQ(1u, BeforeInitialization[1].size());
EXPECT_EQ(2, BeforeInitialization[1][0]);
EXPECT_EQ(3u, TestMachineFunctionCount[1].size());
EXPECT_EQ(24, TestMachineFunctionCount[1][0]);
EXPECT_EQ(27, TestMachineFunctionCount[1][1]);
EXPECT_EQ(30, TestMachineFunctionCount[1][2]);
EXPECT_EQ(1u, BeforeFinalization[1].size());
EXPECT_EQ(32, BeforeFinalization[1][0]);
EXPECT_EQ(32, Count);
// doInitialization returns error
Count = 10000;
MFPM.addPass(TestMachineFunctionPass(Count, BeforeInitialization[1],
BeforeFinalization[1],
TestMachineFunctionCount[1]));
std::string Message;
llvm::handleAllErrors(MFPM.run(*M, MFAM), [&](llvm::StringError &Error) {
Message = Error.getMessage();
});
EXPECT_EQ(Message, DoInitErrMsg);
// doFinalization returns error
Count = 1000;
MFPM.addPass(TestMachineFunctionPass(Count, BeforeInitialization[1],
BeforeFinalization[1],
TestMachineFunctionCount[1]));
llvm::handleAllErrors(MFPM.run(*M, MFAM), [&](llvm::StringError &Error) {
Message = Error.getMessage();
});
EXPECT_EQ(Message, DoFinalErrMsg);
}
} // namespace