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(Str: "x86_64--" )); |
32 | std::string Error; |
33 | const Target *TheTarget = TargetRegistry::lookupTarget(Triple: TT, Error); |
34 | return std::unique_ptr<LLVMTargetMachine>(static_cast<LLVMTargetMachine *>( |
35 | TheTarget->createTargetMachine(TT, CPU: "" , Features: "" , Options: TargetOptions(), RM: std::nullopt, |
36 | CM: std::nullopt, OL: CodeGenOptLevel::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(p: new MachineDominatorTree(MF)); |
54 | MLI.reset(p: new MachineLoopInfo(*MDT)); |
55 | MBPI.reset(p: new MachineBranchProbabilityInfo()); |
56 | MBFI.reset(p: 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(InputData: MIRString); |
71 | Parser = createMIRParser(Contents: std::move(MBuffer), Context); |
72 | if (!Parser) |
73 | report_fatal_error(reason: "null MIRParser" ); |
74 | M = Parser->parseIRModule(); |
75 | if (!M) |
76 | report_fatal_error(reason: "parseIRModule failed" ); |
77 | M->setTargetTriple(TM->getTargetTriple().getTriple()); |
78 | M->setDataLayout(TM->createDataLayout()); |
79 | MMI = std::make_unique<MachineModuleInfo>(args: TM.get()); |
80 | if (Parser->parseMachineFunctions(M&: *M, MMI&: *MMI.get())) |
81 | report_fatal_error(reason: "parseMachineFunctions failed" ); |
82 | } |
83 | |
84 | MachineFunction *getMachineFunction(Module *M, StringRef Name) { |
85 | auto F = M->getFunction(Name); |
86 | if (!F) |
87 | report_fatal_error(reason: "null Function" ); |
88 | auto &MF = MMI->getOrCreateMachineFunction(F&: *F); |
89 | return &MF; |
90 | } |
91 | }; |
92 | |
93 | TEST_F(MachineSizeOptsTest, Test) { |
94 | MachineFunction *F = getMachineFunction(M: M.get(), Name: "f" ); |
95 | ASSERT_TRUE(F != nullptr); |
96 | MachineFunction *G = getMachineFunction(M: M.get(), Name: "g" ); |
97 | ASSERT_TRUE(G != nullptr); |
98 | MachineFunction *H = getMachineFunction(M: M.get(), Name: "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 | |