1 //===- MachineSizeOptsTest.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 "llvm/CodeGen/MachineSizeOpts.h" 10 #include "llvm/Analysis/BlockFrequencyInfo.h" 11 #include "llvm/Analysis/BranchProbabilityInfo.h" 12 #include "llvm/Analysis/LoopInfo.h" 13 #include "llvm/Analysis/ProfileSummaryInfo.h" 14 #include "llvm/CodeGen/MIRParser/MIRParser.h" 15 #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" 16 #include "llvm/CodeGen/MachineBranchProbabilityInfo.h" 17 #include "llvm/CodeGen/MachineDominators.h" 18 #include "llvm/CodeGen/MachineLoopInfo.h" 19 #include "llvm/CodeGen/MachineModuleInfo.h" 20 #include "llvm/IR/Module.h" 21 #include "llvm/MC/TargetRegistry.h" 22 #include "llvm/Support/MemoryBuffer.h" 23 #include "llvm/Support/TargetSelect.h" 24 #include "llvm/Target/TargetMachine.h" 25 #include "gtest/gtest.h" 26 27 using namespace llvm; 28 29 namespace { 30 31 std::unique_ptr<TargetMachine> createTargetMachine() { 32 auto TT(Triple::normalize("x86_64--")); 33 std::string Error; 34 const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error); 35 return std::unique_ptr<TargetMachine>( 36 TheTarget->createTargetMachine(TT, "", "", TargetOptions(), std::nullopt, 37 std::nullopt, CodeGenOptLevel::Default)); 38 } 39 40 class MachineSizeOptsTest : public testing::Test { 41 protected: 42 static const char* MIRString; 43 LLVMContext Context; 44 std::unique_ptr<TargetMachine> TM; 45 std::unique_ptr<MachineModuleInfo> MMI; 46 std::unique_ptr<MIRParser> Parser; 47 std::unique_ptr<Module> M; 48 struct BFIData { 49 std::unique_ptr<MachineDominatorTree> MDT; 50 std::unique_ptr<MachineLoopInfo> MLI; 51 std::unique_ptr<MachineBranchProbabilityInfo> MBPI; 52 std::unique_ptr<MachineBlockFrequencyInfo> MBFI; 53 BFIData(MachineFunction &MF) { 54 MDT.reset(new MachineDominatorTree(MF)); 55 MLI.reset(new MachineLoopInfo(*MDT)); 56 MBPI.reset(new MachineBranchProbabilityInfo()); 57 MBFI.reset(new MachineBlockFrequencyInfo(MF, *MBPI, *MLI)); 58 } 59 MachineBlockFrequencyInfo *get() { return MBFI.get(); } 60 }; 61 62 static void SetUpTestCase() { 63 LLVMInitializeX86TargetInfo(); 64 LLVMInitializeX86Target(); 65 LLVMInitializeX86TargetMC(); 66 } 67 68 void SetUp() override { 69 TM = createTargetMachine(); 70 std::unique_ptr<MemoryBuffer> MBuffer = 71 MemoryBuffer::getMemBuffer(MIRString); 72 Parser = createMIRParser(std::move(MBuffer), Context); 73 if (!Parser) 74 report_fatal_error("null MIRParser"); 75 M = Parser->parseIRModule(); 76 if (!M) 77 report_fatal_error("parseIRModule failed"); 78 M->setTargetTriple(TM->getTargetTriple().getTriple()); 79 M->setDataLayout(TM->createDataLayout()); 80 MMI = std::make_unique<MachineModuleInfo>(TM.get()); 81 if (Parser->parseMachineFunctions(*M, *MMI)) 82 report_fatal_error("parseMachineFunctions failed"); 83 } 84 85 MachineFunction *getMachineFunction(Module *M, StringRef Name) { 86 auto F = M->getFunction(Name); 87 if (!F) 88 report_fatal_error("null Function"); 89 auto &MF = MMI->getOrCreateMachineFunction(*F); 90 return &MF; 91 } 92 }; 93 94 TEST_F(MachineSizeOptsTest, Test) { 95 MachineFunction *F = getMachineFunction(M.get(), "f"); 96 ASSERT_TRUE(F != nullptr); 97 MachineFunction *G = getMachineFunction(M.get(), "g"); 98 ASSERT_TRUE(G != nullptr); 99 MachineFunction *H = getMachineFunction(M.get(), "h"); 100 ASSERT_TRUE(H != nullptr); 101 ProfileSummaryInfo PSI = ProfileSummaryInfo(*M); 102 ASSERT_TRUE(PSI.hasProfileSummary()); 103 BFIData BFID_F(*F); 104 BFIData BFID_G(*G); 105 BFIData BFID_H(*H); 106 MachineBlockFrequencyInfo *MBFI_F = BFID_F.get(); 107 MachineBlockFrequencyInfo *MBFI_G = BFID_G.get(); 108 MachineBlockFrequencyInfo *MBFI_H = BFID_H.get(); 109 MachineBasicBlock &BB0 = F->front(); 110 auto iter = BB0.succ_begin(); 111 MachineBasicBlock *BB1 = *iter; 112 iter++; 113 MachineBasicBlock *BB2 = *iter; 114 iter++; 115 ASSERT_TRUE(iter == BB0.succ_end()); 116 MachineBasicBlock *BB3 = *BB1->succ_begin(); 117 ASSERT_TRUE(BB3 == *BB2->succ_begin()); 118 EXPECT_FALSE(shouldOptimizeForSize(F, &PSI, MBFI_F, PGSOQueryType::Test)); 119 EXPECT_TRUE(shouldOptimizeForSize(G, &PSI, MBFI_G, PGSOQueryType::Test)); 120 EXPECT_FALSE(shouldOptimizeForSize(H, &PSI, MBFI_H, PGSOQueryType::Test)); 121 EXPECT_FALSE(shouldOptimizeForSize(&BB0, &PSI, MBFI_F, PGSOQueryType::Test)); 122 EXPECT_FALSE(shouldOptimizeForSize(BB1, &PSI, MBFI_F, PGSOQueryType::Test)); 123 EXPECT_TRUE(shouldOptimizeForSize(BB2, &PSI, MBFI_F, PGSOQueryType::Test)); 124 EXPECT_FALSE(shouldOptimizeForSize(BB3, &PSI, MBFI_F, PGSOQueryType::Test)); 125 } 126 127 const char* MachineSizeOptsTest::MIRString = R"MIR( 128 --- | 129 define i32 @g(i32 %x) !prof !14 { 130 ret i32 0 131 } 132 133 define i32 @h(i32 %x) !prof !15 { 134 ret i32 0 135 } 136 137 define i32 @f(i32 %x) !prof !16 { 138 bb0: 139 %y1 = icmp eq i32 %x, 0 140 br i1 %y1, label %bb1, label %bb2, !prof !17 141 142 bb1: ; preds = %bb0 143 %z1 = call i32 @g(i32 %x) 144 br label %bb3 145 146 bb2: ; preds = %bb0 147 %z2 = call i32 @h(i32 %x) 148 br label %bb3 149 150 bb3: ; preds = %bb2, %bb1 151 %y2 = phi i32 [ 0, %bb1 ], [ 1, %bb2 ] 152 ret i32 %y2 153 } 154 155 !llvm.module.flags = !{!0} 156 157 !0 = !{i32 1, !"ProfileSummary", !1} 158 !1 = !{!2, !3, !4, !5, !6, !7, !8, !9} 159 !2 = !{!"ProfileFormat", !"InstrProf"} 160 !3 = !{!"TotalCount", i64 10000} 161 !4 = !{!"MaxCount", i64 10} 162 !5 = !{!"MaxInternalCount", i64 1} 163 !6 = !{!"MaxFunctionCount", i64 1000} 164 !7 = !{!"NumCounts", i64 3} 165 !8 = !{!"NumFunctions", i64 3} 166 !9 = !{!"DetailedSummary", !10} 167 !10 = !{!11, !12, !13} 168 !11 = !{i32 10000, i64 1000, i32 1} 169 !12 = !{i32 999000, i64 300, i32 3} 170 !13 = !{i32 999999, i64 5, i32 10} 171 !14 = !{!"function_entry_count", i64 1} 172 !15 = !{!"function_entry_count", i64 100} 173 !16 = !{!"function_entry_count", i64 400} 174 !17 = !{!"branch_weights", i32 100, i32 1} 175 176 ... 177 --- 178 name: g 179 body: | 180 bb.0: 181 %1:gr32 = MOV32r0 implicit-def dead $eflags 182 $eax = COPY %1 183 RET 0, $eax 184 185 ... 186 --- 187 name: h 188 body: | 189 bb.0: 190 %1:gr32 = MOV32r0 implicit-def dead $eflags 191 $eax = COPY %1 192 RET 0, $eax 193 194 ... 195 --- 196 name: f 197 tracksRegLiveness: true 198 body: | 199 bb.0: 200 successors: %bb.1(0x7ebb907a), %bb.2(0x01446f86) 201 liveins: $edi 202 203 %1:gr32 = COPY $edi 204 TEST32rr %1, %1, implicit-def $eflags 205 JCC_1 %bb.2, 5, implicit $eflags 206 JMP_1 %bb.1 207 208 bb.1: 209 successors: %bb.3(0x80000000) 210 211 ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 212 $edi = COPY %1 213 CALL64pcrel32 @g, csr_64, implicit $rsp, implicit $ssp, implicit $edi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax 214 ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 215 %5:gr32 = COPY $eax 216 %4:gr32 = MOV32r0 implicit-def dead $eflags 217 JMP_1 %bb.3 218 219 bb.2: 220 successors: %bb.3(0x80000000) 221 222 ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 223 $edi = COPY %1 224 CALL64pcrel32 @h, csr_64, implicit $rsp, implicit $ssp, implicit $edi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax 225 ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 226 %3:gr32 = COPY $eax 227 %2:gr32 = MOV32ri 1 228 229 bb.3: 230 %0:gr32 = PHI %2, %bb.2, %4, %bb.1 231 $eax = COPY %0 232 RET 0, $eax 233 234 ... 235 )MIR"; 236 237 } // anonymous namespace 238