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 31 using namespace llvm; 32 extern cl::opt<double> CopyWeight; 33 extern cl::opt<double> LoadWeight; 34 extern cl::opt<double> StoreWeight; 35 extern cl::opt<double> CheapRematWeight; 36 extern cl::opt<double> ExpensiveRematWeight; 37 38 namespace { 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 58 enum 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 65 const std::array<MCInstrDesc, MockInstrId::TotalMockInstrs> MockInstrDescs{{ 66 #define MOCK_SPEC(IGNORE, OPCODE, FLAGS) \ 67 {OPCODE, 0, 0, 0, 0, 0, 0, FLAGS, 0, nullptr, nullptr}, 68 MOCK_INSTR(MOCK_SPEC) 69 #undef MOCK_SPEC 70 }}; 71 72 MachineInstr *createMockCopy(MachineFunction &MF) { 73 return MF.CreateMachineInstr(MockInstrDescs[MockInstrId::Copy], DebugLoc()); 74 } 75 76 MachineInstr *createMockLoad(MachineFunction &MF) { 77 return MF.CreateMachineInstr(MockInstrDescs[MockInstrId::Load], DebugLoc()); 78 } 79 80 MachineInstr *createMockStore(MachineFunction &MF) { 81 return MF.CreateMachineInstr(MockInstrDescs[MockInstrId::Store], DebugLoc()); 82 } 83 84 MachineInstr *createMockLoadStore(MachineFunction &MF) { 85 return MF.CreateMachineInstr(MockInstrDescs[MockInstrId::LoadStore], 86 DebugLoc()); 87 } 88 89 MachineInstr *createMockCheapRemat(MachineFunction &MF) { 90 return MF.CreateMachineInstr(MockInstrDescs[MockInstrId::CheapRemat], 91 DebugLoc()); 92 } 93 94 MachineInstr *createMockExpensiveRemat(MachineFunction &MF) { 95 return MF.CreateMachineInstr(MockInstrDescs[MockInstrId::ExpensiveRemat], 96 DebugLoc()); 97 } 98 99 MachineInstr *createMockDebug(MachineFunction &MF) { 100 return MF.CreateMachineInstr(MockInstrDescs[MockInstrId::Dbg], DebugLoc()); 101 } 102 103 MachineInstr *createMockKill(MachineFunction &MF) { 104 return MF.CreateMachineInstr(MockInstrDescs[MockInstrId::Kill], DebugLoc()); 105 } 106 107 MachineInstr *createMockInlineAsm(MachineFunction &MF) { 108 return MF.CreateMachineInstr(MockInstrDescs[MockInstrId::InlAsm], DebugLoc()); 109 } 110 111 TEST(RegAllocScoreTest, SkipDebugKillInlineAsm) { 112 LLVMContext Ctx; 113 Module Mod("Module", Ctx); 114 auto MF = createMachineFunction(Ctx, Mod); 115 116 auto *MBB = MF->CreateMachineBasicBlock(); 117 MF->insert(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(Next, createMockInlineAsm(*MF)); 124 Next = MBB->insertAfter(Next, createMockDebug(*MF)); 125 Next = MBB->insertAfter(Next, createMockKill(*MF)); 126 const auto Score = llvm::calculateRegAllocScore( 127 *MF, MBBFreqMock, [](const MachineInstr &) { return false; }); 128 ASSERT_EQ(MF->size(), 1U); 129 ASSERT_EQ(Score, RegAllocScore()); 130 } 131 132 TEST(RegAllocScoreTest, Counts) { 133 LLVMContext Ctx; 134 Module Mod("Module", Ctx); 135 auto MF = createMachineFunction(Ctx, Mod); 136 137 auto *MBB1 = MF->CreateMachineBasicBlock(); 138 auto *MBB2 = MF->CreateMachineBasicBlock(); 139 MF->insert(MF->end(), MBB1); 140 MF->insert(MF->end(), 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(Next, createMockCopy(*MF)); 152 Next = MBB1->insertAfter(Next, createMockLoad(*MF)); 153 Next = MBB1->insertAfter(Next, createMockLoad(*MF)); 154 Next = MBB1->insertAfter(Next, createMockStore(*MF)); 155 auto *CheapRemat = createMockCheapRemat(*MF); 156 MBB1->insertAfter(Next, CheapRemat); 157 Next = MBB2->end(); 158 Next = MBB2->insertAfter(Next, createMockLoad(*MF)); 159 Next = MBB2->insertAfter(Next, createMockStore(*MF)); 160 Next = MBB2->insertAfter(Next, createMockLoadStore(*MF)); 161 auto *ExpensiveRemat = createMockExpensiveRemat(*MF); 162 MBB2->insertAfter(Next, 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, MBBFreqMock, IsRemat); 169 ASSERT_EQ(Freq1, TotalScore.copyCounts()); 170 ASSERT_EQ(2.0 * Freq1 + Freq2, TotalScore.loadCounts()); 171 ASSERT_EQ(Freq1 + Freq2, TotalScore.storeCounts()); 172 ASSERT_EQ(Freq2, TotalScore.loadStoreCounts()); 173 ASSERT_EQ(Freq1, TotalScore.cheapRematCounts()); 174 ASSERT_EQ(Freq2, TotalScore.expensiveRematCounts()); 175 ASSERT_EQ(TotalScore.getScore(), 176 TotalScore.copyCounts() * CopyWeight + 177 TotalScore.loadCounts() * LoadWeight + 178 TotalScore.storeCounts() * StoreWeight + 179 TotalScore.loadStoreCounts() * (LoadWeight + StoreWeight) + 180 TotalScore.cheapRematCounts() * CheapRematWeight + 181 TotalScore.expensiveRematCounts() * ExpensiveRematWeight 182 183 ); 184 } 185 } // end namespace 186