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