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