1//===- MachineInstrTest.cpp -----------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "../lib/CodeGen/RegAllocScore.h"
10#include "llvm/CodeGen/MachineBasicBlock.h"
11#include "llvm/CodeGen/MachineFunction.h"
12#include "llvm/CodeGen/MachineInstr.h"
13#include "llvm/CodeGen/MachineMemOperand.h"
14#include "llvm/CodeGen/MachineModuleInfo.h"
15#include "llvm/CodeGen/TargetFrameLowering.h"
16#include "llvm/CodeGen/TargetInstrInfo.h"
17#include "llvm/CodeGen/TargetLowering.h"
18#include "llvm/CodeGen/TargetSubtargetInfo.h"
19#include "llvm/IR/DebugInfoMetadata.h"
20#include "llvm/IR/IRBuilder.h"
21#include "llvm/IR/ModuleSlotTracker.h"
22#include "llvm/MC/MCAsmInfo.h"
23#include "llvm/MC/MCSymbol.h"
24#include "llvm/MC/TargetRegistry.h"
25#include "llvm/Support/TargetSelect.h"
26#include "llvm/Target/TargetMachine.h"
27#include "llvm/Target/TargetOptions.h"
28#include "llvm/TargetParser/Triple.h"
29#include "gtest/gtest.h"
30
31using namespace llvm;
32extern cl::opt<double> CopyWeight;
33extern cl::opt<double> LoadWeight;
34extern cl::opt<double> StoreWeight;
35extern cl::opt<double> CheapRematWeight;
36extern cl::opt<double> ExpensiveRematWeight;
37
38namespace {
39// Include helper functions to ease the manipulation of MachineFunctions.
40#include "MFCommon.inc"
41
42// MachineFunction::CreateMachineInstr doesn't copy the MCInstrDesc, it
43// takes its address. So we want a bunch of pre-allocated mock MCInstrDescs.
44#define MOCK_INSTR(MACRO) \
45 MACRO(Copy, TargetOpcode::COPY, 0) \
46 MACRO(Load, 0, 1ULL << MCID::MayLoad) \
47 MACRO(Store, 0, 1ULL << MCID::MayStore) \
48 MACRO(LoadStore, 0, (1ULL << MCID::MayLoad) | (1ULL << MCID::MayStore)) \
49 MACRO(CheapRemat, 0, 1ULL << MCID::CheapAsAMove) \
50 MACRO(ExpensiveRemat, 0, 0) \
51 MACRO(Dbg, TargetOpcode::DBG_LABEL, \
52 (1ULL << MCID::MayLoad) | (1ULL << MCID::MayStore)) \
53 MACRO(InlAsm, TargetOpcode::INLINEASM, \
54 (1ULL << MCID::MayLoad) | (1ULL << MCID::MayStore)) \
55 MACRO(Kill, TargetOpcode::KILL, \
56 (1ULL << MCID::MayLoad) | (1ULL << MCID::MayStore))
57
58enum MockInstrId {
59#define MOCK_INSTR_ID(ID, IGNORE, IGNORE2) ID,
60 MOCK_INSTR(MOCK_INSTR_ID)
61#undef MOCK_INSTR_ID
62 TotalMockInstrs
63};
64
65const std::array<MCInstrDesc, MockInstrId::TotalMockInstrs> MockInstrDescs{._M_elems: {
66#define MOCK_SPEC(IGNORE, OPCODE, FLAGS) \
67 {OPCODE, 0, 0, 0, 0, 0, 0, 0, 0, FLAGS, 0},
68 MOCK_INSTR(MOCK_SPEC)
69#undef MOCK_SPEC
70}};
71
72MachineInstr *createMockCopy(MachineFunction &MF) {
73 return MF.CreateMachineInstr(MCID: MockInstrDescs[MockInstrId::Copy], DL: DebugLoc());
74}
75
76MachineInstr *createMockLoad(MachineFunction &MF) {
77 return MF.CreateMachineInstr(MCID: MockInstrDescs[MockInstrId::Load], DL: DebugLoc());
78}
79
80MachineInstr *createMockStore(MachineFunction &MF) {
81 return MF.CreateMachineInstr(MCID: MockInstrDescs[MockInstrId::Store], DL: DebugLoc());
82}
83
84MachineInstr *createMockLoadStore(MachineFunction &MF) {
85 return MF.CreateMachineInstr(MCID: MockInstrDescs[MockInstrId::LoadStore],
86 DL: DebugLoc());
87}
88
89MachineInstr *createMockCheapRemat(MachineFunction &MF) {
90 return MF.CreateMachineInstr(MCID: MockInstrDescs[MockInstrId::CheapRemat],
91 DL: DebugLoc());
92}
93
94MachineInstr *createMockExpensiveRemat(MachineFunction &MF) {
95 return MF.CreateMachineInstr(MCID: MockInstrDescs[MockInstrId::ExpensiveRemat],
96 DL: DebugLoc());
97}
98
99MachineInstr *createMockDebug(MachineFunction &MF) {
100 return MF.CreateMachineInstr(MCID: MockInstrDescs[MockInstrId::Dbg], DL: DebugLoc());
101}
102
103MachineInstr *createMockKill(MachineFunction &MF) {
104 return MF.CreateMachineInstr(MCID: MockInstrDescs[MockInstrId::Kill], DL: DebugLoc());
105}
106
107MachineInstr *createMockInlineAsm(MachineFunction &MF) {
108 return MF.CreateMachineInstr(MCID: MockInstrDescs[MockInstrId::InlAsm], DL: DebugLoc());
109}
110
111TEST(RegAllocScoreTest, SkipDebugKillInlineAsm) {
112 LLVMContext Ctx;
113 Module Mod("Module", Ctx);
114 auto MF = createMachineFunction(Ctx, M&: Mod);
115
116 auto *MBB = MF->CreateMachineBasicBlock();
117 MF->insert(MBBI: MF->end(), MBB);
118 auto MBBFreqMock = [&](const MachineBasicBlock &_MBB) -> double {
119 assert(&_MBB == MBB);
120 return 0.5;
121 };
122 auto Next = MBB->end();
123 Next = MBB->insertAfter(I: Next, MI: createMockInlineAsm(MF&: *MF));
124 Next = MBB->insertAfter(I: Next, MI: createMockDebug(MF&: *MF));
125 Next = MBB->insertAfter(I: Next, MI: createMockKill(MF&: *MF));
126 const auto Score = llvm::calculateRegAllocScore(
127 MF: *MF, GetBBFreq: MBBFreqMock, IsTriviallyRematerializable: [](const MachineInstr &) { return false; });
128 ASSERT_EQ(MF->size(), 1U);
129 ASSERT_EQ(Score, RegAllocScore());
130}
131
132TEST(RegAllocScoreTest, Counts) {
133 LLVMContext Ctx;
134 Module Mod("Module", Ctx);
135 auto MF = createMachineFunction(Ctx, M&: Mod);
136
137 auto *MBB1 = MF->CreateMachineBasicBlock();
138 auto *MBB2 = MF->CreateMachineBasicBlock();
139 MF->insert(MBBI: MF->end(), MBB: MBB1);
140 MF->insert(MBBI: MF->end(), MBB: MBB2);
141 const double Freq1 = 0.5;
142 const double Freq2 = 10.0;
143 auto MBBFreqMock = [&](const MachineBasicBlock &MBB) -> double {
144 if (&MBB == MBB1)
145 return Freq1;
146 if (&MBB == MBB2)
147 return Freq2;
148 llvm_unreachable("We only created 2 basic blocks");
149 };
150 auto Next = MBB1->end();
151 Next = MBB1->insertAfter(I: Next, MI: createMockCopy(MF&: *MF));
152 Next = MBB1->insertAfter(I: Next, MI: createMockLoad(MF&: *MF));
153 Next = MBB1->insertAfter(I: Next, MI: createMockLoad(MF&: *MF));
154 Next = MBB1->insertAfter(I: Next, MI: createMockStore(MF&: *MF));
155 auto *CheapRemat = createMockCheapRemat(MF&: *MF);
156 MBB1->insertAfter(I: Next, MI: CheapRemat);
157 Next = MBB2->end();
158 Next = MBB2->insertAfter(I: Next, MI: createMockLoad(MF&: *MF));
159 Next = MBB2->insertAfter(I: Next, MI: createMockStore(MF&: *MF));
160 Next = MBB2->insertAfter(I: Next, MI: createMockLoadStore(MF&: *MF));
161 auto *ExpensiveRemat = createMockExpensiveRemat(MF&: *MF);
162 MBB2->insertAfter(I: Next, MI: ExpensiveRemat);
163 auto IsRemat = [&](const MachineInstr &MI) {
164 return &MI == CheapRemat || &MI == ExpensiveRemat;
165 };
166 ASSERT_EQ(MF->size(), 2U);
167 const auto TotalScore =
168 llvm::calculateRegAllocScore(MF: *MF, GetBBFreq: MBBFreqMock, IsTriviallyRematerializable: IsRemat);
169 ASSERT_DOUBLE_EQ(Freq1, TotalScore.copyCounts());
170 ASSERT_DOUBLE_EQ(2.0 * Freq1 + Freq2, TotalScore.loadCounts());
171 ASSERT_DOUBLE_EQ(Freq1 + Freq2, TotalScore.storeCounts());
172 ASSERT_DOUBLE_EQ(Freq2, TotalScore.loadStoreCounts());
173 ASSERT_DOUBLE_EQ(Freq1, TotalScore.cheapRematCounts());
174 ASSERT_DOUBLE_EQ(Freq2, TotalScore.expensiveRematCounts());
175 ASSERT_DOUBLE_EQ(
176 TotalScore.getScore(),
177 TotalScore.copyCounts() * CopyWeight +
178 TotalScore.loadCounts() * LoadWeight +
179 TotalScore.storeCounts() * StoreWeight +
180 TotalScore.loadStoreCounts() * (LoadWeight + StoreWeight) +
181 TotalScore.cheapRematCounts() * CheapRematWeight +
182 TotalScore.expensiveRematCounts() * ExpensiveRematWeight
183
184 );
185}
186} // end namespace
187

source code of llvm/unittests/CodeGen/RegAllocScoreTest.cpp