llvm-project/llvm/unittests/CodeGen/RegAllocScoreTest.cpp
Matin Raayai bb3f5e1fed
Overhaul the TargetMachine and LLVMTargetMachine Classes (#111234)
Following discussions in #110443, and the following earlier discussions
in https://lists.llvm.org/pipermail/llvm-dev/2017-October/117907.html,
https://reviews.llvm.org/D38482, https://reviews.llvm.org/D38489, this
PR attempts to overhaul the `TargetMachine` and `LLVMTargetMachine`
interface classes. More specifically:
1. Makes `TargetMachine` the only class implemented under
`TargetMachine.h` in the `Target` library.
2. `TargetMachine` contains target-specific interface functions that
relate to IR/CodeGen/MC constructs, whereas before (at least on paper)
it was supposed to have only IR/MC constructs. Any Target that doesn't
want to use the independent code generator simply does not implement
them, and returns either `false` or `nullptr`.
3. Renames `LLVMTargetMachine` to `CodeGenCommonTMImpl`. This renaming
aims to make the purpose of `LLVMTargetMachine` clearer. Its interface
was moved under the CodeGen library, to further emphasis its usage in
Targets that use CodeGen directly.
4. Makes `TargetMachine` the only interface used across LLVM and its
projects. With these changes, `CodeGenCommonTMImpl` is simply a set of
shared function implementations of `TargetMachine`, and CodeGen users
don't need to static cast to `LLVMTargetMachine` every time they need a
CodeGen-specific feature of the `TargetMachine`.
5. More importantly, does not change any requirements regarding library
linking.

cc @arsenm @aeubanks
2024-11-14 13:30:05 -08:00

188 lines
7.2 KiB
C++

//===- MachineInstrTest.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 "../lib/CodeGen/RegAllocScore.h"
#include "llvm/CodeGen/CodeGenTargetMachineImpl.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ModuleSlotTracker.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/TargetParser/Triple.h"
#include "gtest/gtest.h"
using namespace llvm;
extern cl::opt<double> CopyWeight;
extern cl::opt<double> LoadWeight;
extern cl::opt<double> StoreWeight;
extern cl::opt<double> CheapRematWeight;
extern cl::opt<double> ExpensiveRematWeight;
namespace {
// Include helper functions to ease the manipulation of MachineFunctions.
#include "MFCommon.inc"
// MachineFunction::CreateMachineInstr doesn't copy the MCInstrDesc, it
// takes its address. So we want a bunch of pre-allocated mock MCInstrDescs.
#define MOCK_INSTR(MACRO) \
MACRO(Copy, TargetOpcode::COPY, 0) \
MACRO(Load, 0, 1ULL << MCID::MayLoad) \
MACRO(Store, 0, 1ULL << MCID::MayStore) \
MACRO(LoadStore, 0, (1ULL << MCID::MayLoad) | (1ULL << MCID::MayStore)) \
MACRO(CheapRemat, 0, 1ULL << MCID::CheapAsAMove) \
MACRO(ExpensiveRemat, 0, 0) \
MACRO(Dbg, TargetOpcode::DBG_LABEL, \
(1ULL << MCID::MayLoad) | (1ULL << MCID::MayStore)) \
MACRO(InlAsm, TargetOpcode::INLINEASM, \
(1ULL << MCID::MayLoad) | (1ULL << MCID::MayStore)) \
MACRO(Kill, TargetOpcode::KILL, \
(1ULL << MCID::MayLoad) | (1ULL << MCID::MayStore))
enum MockInstrId {
#define MOCK_INSTR_ID(ID, IGNORE, IGNORE2) ID,
MOCK_INSTR(MOCK_INSTR_ID)
#undef MOCK_INSTR_ID
TotalMockInstrs
};
const std::array<MCInstrDesc, MockInstrId::TotalMockInstrs> MockInstrDescs{{
#define MOCK_SPEC(IGNORE, OPCODE, FLAGS) \
{OPCODE, 0, 0, 0, 0, 0, 0, 0, 0, FLAGS, 0},
MOCK_INSTR(MOCK_SPEC)
#undef MOCK_SPEC
}};
MachineInstr *createMockCopy(MachineFunction &MF) {
return MF.CreateMachineInstr(MockInstrDescs[MockInstrId::Copy], DebugLoc());
}
MachineInstr *createMockLoad(MachineFunction &MF) {
return MF.CreateMachineInstr(MockInstrDescs[MockInstrId::Load], DebugLoc());
}
MachineInstr *createMockStore(MachineFunction &MF) {
return MF.CreateMachineInstr(MockInstrDescs[MockInstrId::Store], DebugLoc());
}
MachineInstr *createMockLoadStore(MachineFunction &MF) {
return MF.CreateMachineInstr(MockInstrDescs[MockInstrId::LoadStore],
DebugLoc());
}
MachineInstr *createMockCheapRemat(MachineFunction &MF) {
return MF.CreateMachineInstr(MockInstrDescs[MockInstrId::CheapRemat],
DebugLoc());
}
MachineInstr *createMockExpensiveRemat(MachineFunction &MF) {
return MF.CreateMachineInstr(MockInstrDescs[MockInstrId::ExpensiveRemat],
DebugLoc());
}
MachineInstr *createMockDebug(MachineFunction &MF) {
return MF.CreateMachineInstr(MockInstrDescs[MockInstrId::Dbg], DebugLoc());
}
MachineInstr *createMockKill(MachineFunction &MF) {
return MF.CreateMachineInstr(MockInstrDescs[MockInstrId::Kill], DebugLoc());
}
MachineInstr *createMockInlineAsm(MachineFunction &MF) {
return MF.CreateMachineInstr(MockInstrDescs[MockInstrId::InlAsm], DebugLoc());
}
TEST(RegAllocScoreTest, SkipDebugKillInlineAsm) {
LLVMContext Ctx;
Module Mod("Module", Ctx);
auto MF = createMachineFunction(Ctx, Mod);
auto *MBB = MF->CreateMachineBasicBlock();
MF->insert(MF->end(), MBB);
auto MBBFreqMock = [&](const MachineBasicBlock &_MBB) -> double {
assert(&_MBB == MBB);
return 0.5;
};
auto Next = MBB->end();
Next = MBB->insertAfter(Next, createMockInlineAsm(*MF));
Next = MBB->insertAfter(Next, createMockDebug(*MF));
Next = MBB->insertAfter(Next, createMockKill(*MF));
const auto Score = llvm::calculateRegAllocScore(
*MF, MBBFreqMock, [](const MachineInstr &) { return false; });
ASSERT_EQ(MF->size(), 1U);
ASSERT_EQ(Score, RegAllocScore());
}
TEST(RegAllocScoreTest, Counts) {
LLVMContext Ctx;
Module Mod("Module", Ctx);
auto MF = createMachineFunction(Ctx, Mod);
auto *MBB1 = MF->CreateMachineBasicBlock();
auto *MBB2 = MF->CreateMachineBasicBlock();
MF->insert(MF->end(), MBB1);
MF->insert(MF->end(), MBB2);
const double Freq1 = 0.5;
const double Freq2 = 10.0;
auto MBBFreqMock = [&](const MachineBasicBlock &MBB) -> double {
if (&MBB == MBB1)
return Freq1;
if (&MBB == MBB2)
return Freq2;
llvm_unreachable("We only created 2 basic blocks");
};
auto Next = MBB1->end();
Next = MBB1->insertAfter(Next, createMockCopy(*MF));
Next = MBB1->insertAfter(Next, createMockLoad(*MF));
Next = MBB1->insertAfter(Next, createMockLoad(*MF));
Next = MBB1->insertAfter(Next, createMockStore(*MF));
auto *CheapRemat = createMockCheapRemat(*MF);
MBB1->insertAfter(Next, CheapRemat);
Next = MBB2->end();
Next = MBB2->insertAfter(Next, createMockLoad(*MF));
Next = MBB2->insertAfter(Next, createMockStore(*MF));
Next = MBB2->insertAfter(Next, createMockLoadStore(*MF));
auto *ExpensiveRemat = createMockExpensiveRemat(*MF);
MBB2->insertAfter(Next, ExpensiveRemat);
auto IsRemat = [&](const MachineInstr &MI) {
return &MI == CheapRemat || &MI == ExpensiveRemat;
};
ASSERT_EQ(MF->size(), 2U);
const auto TotalScore =
llvm::calculateRegAllocScore(*MF, MBBFreqMock, IsRemat);
ASSERT_DOUBLE_EQ(Freq1, TotalScore.copyCounts());
ASSERT_DOUBLE_EQ(2.0 * Freq1 + Freq2, TotalScore.loadCounts());
ASSERT_DOUBLE_EQ(Freq1 + Freq2, TotalScore.storeCounts());
ASSERT_DOUBLE_EQ(Freq2, TotalScore.loadStoreCounts());
ASSERT_DOUBLE_EQ(Freq1, TotalScore.cheapRematCounts());
ASSERT_DOUBLE_EQ(Freq2, TotalScore.expensiveRematCounts());
ASSERT_DOUBLE_EQ(
TotalScore.getScore(),
TotalScore.copyCounts() * CopyWeight +
TotalScore.loadCounts() * LoadWeight +
TotalScore.storeCounts() * StoreWeight +
TotalScore.loadStoreCounts() * (LoadWeight + StoreWeight) +
TotalScore.cheapRematCounts() * CheapRematWeight +
TotalScore.expensiveRematCounts() * ExpensiveRematWeight
);
}
} // end namespace