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