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