xref: /llvm-project/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp (revision b8f191e054dd136dfe7448c9c304884bdcf6a88c)
1 //===- FunctionPropertiesAnalysisTest.cpp - Function Properties Unit Tests-===//
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/Analysis/FunctionPropertiesAnalysis.h"
10 #include "llvm/ADT/iterator_range.h"
11 #include "llvm/Analysis/AliasAnalysis.h"
12 #include "llvm/Analysis/LoopInfo.h"
13 #include "llvm/AsmParser/Parser.h"
14 #include "llvm/IR/Dominators.h"
15 #include "llvm/IR/Instructions.h"
16 #include "llvm/IR/LLVMContext.h"
17 #include "llvm/IR/Module.h"
18 #include "llvm/IR/PassManager.h"
19 #include "llvm/Passes/PassBuilder.h"
20 #include "llvm/Passes/StandardInstrumentations.h"
21 #include "llvm/Support/SourceMgr.h"
22 #include "llvm/Transforms/Utils/Cloning.h"
23 #include "gtest/gtest.h"
24 #include <cstring>
25 
26 using namespace llvm;
27 
28 extern cl::opt<bool> EnableDetailedFunctionProperties;
29 extern cl::opt<bool> BigBasicBlockInstructionThreshold;
30 extern cl::opt<bool> MediumBasicBlockInstrutionThreshold;
31 
32 namespace {
33 
34 class FunctionPropertiesAnalysisTest : public testing::Test {
35 public:
36   FunctionPropertiesAnalysisTest() {
37     FAM.registerPass([&] { return DominatorTreeAnalysis(); });
38     FAM.registerPass([&] { return LoopAnalysis(); });
39     FAM.registerPass([&] { return PassInstrumentationAnalysis(); });
40   }
41 
42 protected:
43   std::unique_ptr<DominatorTree> DT;
44   std::unique_ptr<LoopInfo> LI;
45   FunctionAnalysisManager FAM;
46 
47   FunctionPropertiesInfo buildFPI(Function &F) {
48     return FunctionPropertiesInfo::getFunctionPropertiesInfo(F, FAM);
49   }
50 
51   void invalidate(Function &F) {
52     PreservedAnalyses PA = PreservedAnalyses::none();
53     FAM.invalidate(F, PA);
54   }
55 
56   std::unique_ptr<Module> makeLLVMModule(LLVMContext &C, const char *IR) {
57     SMDiagnostic Err;
58     std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
59     if (!Mod)
60       Err.print("MLAnalysisTests", errs());
61     return Mod;
62   }
63 
64   CallBase* findCall(Function& F, const char* Name = nullptr) {
65     for (auto &BB : F)
66       for (auto &I : BB )
67         if (auto *CB = dyn_cast<CallBase>(&I))
68           if (!Name || CB->getName() == Name)
69             return CB;
70     return nullptr;
71   }
72 };
73 
74 TEST_F(FunctionPropertiesAnalysisTest, BasicTest) {
75   LLVMContext C;
76   std::unique_ptr<Module> M = makeLLVMModule(C,
77                                              R"IR(
78 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
79 target triple = "x86_64-pc-linux-gnu"
80 declare i32 @f1(i32)
81 declare i32 @f2(i32)
82 define i32 @branches(i32) {
83   %cond = icmp slt i32 %0, 3
84   br i1 %cond, label %then, label %else
85 then:
86   %ret.1 = call i32 @f1(i32 %0)
87   br label %last.block
88 else:
89   %ret.2 = call i32 @f2(i32 %0)
90   br label %last.block
91 last.block:
92   %ret = phi i32 [%ret.1, %then], [%ret.2, %else]
93   ret i32 %ret
94 }
95 define internal i32 @top() {
96   %1 = call i32 @branches(i32 2)
97   %2 = call i32 @f1(i32 %1)
98   ret i32 %2
99 }
100 )IR");
101 
102   Function *BranchesFunction = M->getFunction("branches");
103   FunctionPropertiesInfo BranchesFeatures = buildFPI(*BranchesFunction);
104   EXPECT_EQ(BranchesFeatures.BasicBlockCount, 4);
105   EXPECT_EQ(BranchesFeatures.BlocksReachedFromConditionalInstruction, 2);
106   // 2 Users: top is one. The other is added because @branches is not internal,
107   // so it may have external callers.
108   EXPECT_EQ(BranchesFeatures.Uses, 2);
109   EXPECT_EQ(BranchesFeatures.DirectCallsToDefinedFunctions, 0);
110   EXPECT_EQ(BranchesFeatures.LoadInstCount, 0);
111   EXPECT_EQ(BranchesFeatures.StoreInstCount, 0);
112   EXPECT_EQ(BranchesFeatures.MaxLoopDepth, 0);
113   EXPECT_EQ(BranchesFeatures.TopLevelLoopCount, 0);
114 
115   Function *TopFunction = M->getFunction("top");
116   FunctionPropertiesInfo TopFeatures = buildFPI(*TopFunction);
117   EXPECT_EQ(TopFeatures.BasicBlockCount, 1);
118   EXPECT_EQ(TopFeatures.BlocksReachedFromConditionalInstruction, 0);
119   EXPECT_EQ(TopFeatures.Uses, 0);
120   EXPECT_EQ(TopFeatures.DirectCallsToDefinedFunctions, 1);
121   EXPECT_EQ(BranchesFeatures.LoadInstCount, 0);
122   EXPECT_EQ(BranchesFeatures.StoreInstCount, 0);
123   EXPECT_EQ(BranchesFeatures.MaxLoopDepth, 0);
124   EXPECT_EQ(BranchesFeatures.TopLevelLoopCount, 0);
125 
126   EnableDetailedFunctionProperties.setValue(true);
127   FunctionPropertiesInfo DetailedBranchesFeatures = buildFPI(*BranchesFunction);
128   EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithSingleSuccessor, 2);
129   EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithTwoSuccessors, 1);
130   EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithMoreThanTwoSuccessors, 0);
131   EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithSinglePredecessor, 2);
132   EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithTwoPredecessors, 1);
133   EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithMoreThanTwoPredecessors, 0);
134   EXPECT_EQ(DetailedBranchesFeatures.BigBasicBlocks, 0);
135   EXPECT_EQ(DetailedBranchesFeatures.MediumBasicBlocks, 0);
136   EXPECT_EQ(DetailedBranchesFeatures.SmallBasicBlocks, 4);
137   EXPECT_EQ(DetailedBranchesFeatures.CastInstructionCount, 0);
138   EXPECT_EQ(DetailedBranchesFeatures.FloatingPointInstructionCount, 0);
139   EXPECT_EQ(DetailedBranchesFeatures.IntegerInstructionCount, 4);
140   EXPECT_EQ(DetailedBranchesFeatures.ConstantIntOperandCount, 1);
141   EXPECT_EQ(DetailedBranchesFeatures.ConstantFPOperandCount, 0);
142   EXPECT_EQ(DetailedBranchesFeatures.ConstantOperandCount, 0);
143   EXPECT_EQ(DetailedBranchesFeatures.InstructionOperandCount, 4);
144   EXPECT_EQ(DetailedBranchesFeatures.BasicBlockOperandCount, 4);
145   EXPECT_EQ(DetailedBranchesFeatures.GlobalValueOperandCount, 2);
146   EXPECT_EQ(DetailedBranchesFeatures.InlineAsmOperandCount, 0);
147   EXPECT_EQ(DetailedBranchesFeatures.ArgumentOperandCount, 3);
148   EXPECT_EQ(DetailedBranchesFeatures.UnknownOperandCount, 0);
149   EnableDetailedFunctionProperties.setValue(false);
150 }
151 
152 TEST_F(FunctionPropertiesAnalysisTest, DifferentPredecessorSuccessorCounts) {
153   LLVMContext C;
154   std::unique_ptr<Module> M = makeLLVMModule(C,
155                                              R"IR(
156 define i64 @f1() {
157   br i1 0, label %br1, label %finally
158 br1:
159   ret i64 0
160 finally:
161   ret i64 3
162 }
163 )IR");
164 
165   Function *F1 = M->getFunction("f1");
166   EnableDetailedFunctionProperties.setValue(true);
167   FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);
168   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithSingleSuccessor, 0);
169   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithTwoSuccessors, 1);
170   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithMoreThanTwoSuccessors, 0);
171   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithSinglePredecessor, 2);
172   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithTwoPredecessors, 0);
173   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithMoreThanTwoPredecessors, 0);
174   EXPECT_EQ(DetailedF1Properties.BigBasicBlocks, 0);
175   EXPECT_EQ(DetailedF1Properties.MediumBasicBlocks, 0);
176   EXPECT_EQ(DetailedF1Properties.SmallBasicBlocks, 3);
177   EXPECT_EQ(DetailedF1Properties.CastInstructionCount, 0);
178   EXPECT_EQ(DetailedF1Properties.FloatingPointInstructionCount, 0);
179   EXPECT_EQ(DetailedF1Properties.IntegerInstructionCount, 0);
180   EXPECT_EQ(DetailedF1Properties.ConstantIntOperandCount, 3);
181   EXPECT_EQ(DetailedF1Properties.ConstantFPOperandCount, 0);
182   EXPECT_EQ(DetailedF1Properties.ConstantOperandCount, 0);
183   EXPECT_EQ(DetailedF1Properties.InstructionOperandCount, 0);
184   EXPECT_EQ(DetailedF1Properties.BasicBlockOperandCount, 2);
185   EXPECT_EQ(DetailedF1Properties.GlobalValueOperandCount, 0);
186   EXPECT_EQ(DetailedF1Properties.InlineAsmOperandCount, 0);
187   EXPECT_EQ(DetailedF1Properties.ArgumentOperandCount, 0);
188   EXPECT_EQ(DetailedF1Properties.UnknownOperandCount, 0);
189   EnableDetailedFunctionProperties.setValue(false);
190 }
191 
192 TEST_F(FunctionPropertiesAnalysisTest, InlineSameBBSimple) {
193   LLVMContext C;
194   std::unique_ptr<Module> M = makeLLVMModule(C,
195                                              R"IR(
196 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
197 target triple = "x86_64-pc-linux-gnu"
198 define i32 @f1(i32 %a) {
199   %b = call i32 @f2(i32 %a)
200   %c = add i32 %b, 2
201   ret i32 %c
202 }
203 
204 define i32 @f2(i32 %a) {
205   %b = add i32 %a, 1
206   ret i32 %b
207 }
208 )IR");
209 
210   Function *F1 = M->getFunction("f1");
211   CallBase* CB = findCall(*F1, "b");
212   EXPECT_NE(CB, nullptr);
213 
214   FunctionPropertiesInfo ExpectedInitial;
215   ExpectedInitial.BasicBlockCount = 1;
216   ExpectedInitial.TotalInstructionCount = 3;
217   ExpectedInitial.Uses = 1;
218   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
219 
220   FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;
221   ExpectedFinal.DirectCallsToDefinedFunctions = 0;
222 
223   auto FPI = buildFPI(*F1);
224   EXPECT_EQ(FPI, ExpectedInitial);
225 
226   FunctionPropertiesUpdater FPU(FPI, *CB);
227   InlineFunctionInfo IFI;
228   auto IR = llvm::InlineFunction(*CB, IFI);
229   EXPECT_TRUE(IR.isSuccess());
230   invalidate(*F1);
231   EXPECT_TRUE(FPU.finishAndTest(FAM));
232   EXPECT_EQ(FPI, ExpectedFinal);
233 }
234 
235 TEST_F(FunctionPropertiesAnalysisTest, InlineSameBBLargerCFG) {
236   LLVMContext C;
237   std::unique_ptr<Module> M = makeLLVMModule(C,
238                                              R"IR(
239 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
240 target triple = "x86_64-pc-linux-gnu"
241 define i32 @f1(i32 %a) {
242 entry:
243   %i = icmp slt i32 %a, 0
244   br i1 %i, label %if.then, label %if.else
245 if.then:
246   %b = call i32 @f2(i32 %a)
247   %c1 = add i32 %b, 2
248   br label %end
249 if.else:
250   %c2 = add i32 %a, 1
251   br label %end
252 end:
253   %ret = phi i32 [%c1, %if.then],[%c2, %if.else]
254   ret i32 %ret
255 }
256 
257 define i32 @f2(i32 %a) {
258   %b = add i32 %a, 1
259   ret i32 %b
260 }
261 )IR");
262 
263   Function *F1 = M->getFunction("f1");
264   CallBase* CB = findCall(*F1, "b");
265   EXPECT_NE(CB, nullptr);
266 
267   FunctionPropertiesInfo ExpectedInitial;
268   ExpectedInitial.BasicBlockCount = 4;
269   ExpectedInitial.BlocksReachedFromConditionalInstruction = 2;
270   ExpectedInitial.TotalInstructionCount = 9;
271   ExpectedInitial.Uses = 1;
272   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
273 
274   FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;
275   ExpectedFinal.DirectCallsToDefinedFunctions = 0;
276 
277   auto FPI = buildFPI(*F1);
278   EXPECT_EQ(FPI, ExpectedInitial);
279 
280   FunctionPropertiesUpdater FPU(FPI, *CB);
281   InlineFunctionInfo IFI;
282   auto IR = llvm::InlineFunction(*CB, IFI);
283   EXPECT_TRUE(IR.isSuccess());
284   invalidate(*F1);
285   EXPECT_TRUE(FPU.finishAndTest(FAM));
286   EXPECT_EQ(FPI, ExpectedFinal);
287 }
288 
289 TEST_F(FunctionPropertiesAnalysisTest, InlineSameBBLoops) {
290   LLVMContext C;
291   std::unique_ptr<Module> M = makeLLVMModule(C,
292                                              R"IR(
293 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
294 target triple = "x86_64-pc-linux-gnu"
295 define i32 @f1(i32 %a) {
296 entry:
297   %i = icmp slt i32 %a, 0
298   br i1 %i, label %if.then, label %if.else
299 if.then:
300   %b = call i32 @f2(i32 %a)
301   %c1 = add i32 %b, 2
302   br label %end
303 if.else:
304   %c2 = add i32 %a, 1
305   br label %end
306 end:
307   %ret = phi i32 [%c1, %if.then],[%c2, %if.else]
308   ret i32 %ret
309 }
310 
311 define i32 @f2(i32 %a) {
312 entry:
313   br label %loop
314 loop:
315   %indvar = phi i32 [%indvar.next, %loop], [0, %entry]
316   %b = add i32 %a, %indvar
317   %indvar.next = add i32 %indvar, 1
318   %cond = icmp slt i32 %indvar.next, %a
319   br i1 %cond, label %loop, label %exit
320 exit:
321   ret i32 %b
322 }
323 )IR");
324 
325   Function *F1 = M->getFunction("f1");
326   CallBase* CB = findCall(*F1, "b");
327   EXPECT_NE(CB, nullptr);
328 
329   FunctionPropertiesInfo ExpectedInitial;
330   ExpectedInitial.BasicBlockCount = 4;
331   ExpectedInitial.BlocksReachedFromConditionalInstruction = 2;
332   ExpectedInitial.TotalInstructionCount = 9;
333   ExpectedInitial.Uses = 1;
334   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
335 
336   FunctionPropertiesInfo ExpectedFinal;
337   ExpectedFinal.BasicBlockCount = 6;
338   ExpectedFinal.BlocksReachedFromConditionalInstruction = 4;
339   ExpectedFinal.Uses = 1;
340   ExpectedFinal.MaxLoopDepth = 1;
341   ExpectedFinal.TopLevelLoopCount = 1;
342   ExpectedFinal.TotalInstructionCount = 14;
343 
344   auto FPI = buildFPI(*F1);
345   EXPECT_EQ(FPI, ExpectedInitial);
346   FunctionPropertiesUpdater FPU(FPI, *CB);
347   InlineFunctionInfo IFI;
348 
349   auto IR = llvm::InlineFunction(*CB, IFI);
350   EXPECT_TRUE(IR.isSuccess());
351   invalidate(*F1);
352   EXPECT_TRUE(FPU.finishAndTest(FAM));
353   EXPECT_EQ(FPI, ExpectedFinal);
354 }
355 
356 TEST_F(FunctionPropertiesAnalysisTest, InvokeSimple) {
357   LLVMContext C;
358   std::unique_ptr<Module> M = makeLLVMModule(C,
359                                              R"IR(
360 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
361 target triple = "x86_64-pc-linux-gnu"
362 declare void @might_throw()
363 
364 define internal void @callee() {
365 entry:
366   call void @might_throw()
367   ret void
368 }
369 
370 define i32 @caller() personality i32 (...)* @__gxx_personality_v0 {
371 entry:
372   invoke void @callee()
373       to label %cont unwind label %exc
374 
375 cont:
376   ret i32 0
377 
378 exc:
379   %exn = landingpad {i8*, i32}
380          cleanup
381   ret i32 1
382 }
383 
384 declare i32 @__gxx_personality_v0(...)
385 )IR");
386 
387   Function *F1 = M->getFunction("caller");
388   CallBase* CB = findCall(*F1);
389   EXPECT_NE(CB, nullptr);
390 
391   auto FPI = buildFPI(*F1);
392   FunctionPropertiesUpdater FPU(FPI, *CB);
393   InlineFunctionInfo IFI;
394   auto IR = llvm::InlineFunction(*CB, IFI);
395   EXPECT_TRUE(IR.isSuccess());
396   invalidate(*F1);
397   EXPECT_TRUE(FPU.finishAndTest(FAM));
398   EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size());
399   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
400             F1->getInstructionCount());
401 }
402 
403 TEST_F(FunctionPropertiesAnalysisTest, InvokeUnreachableHandler) {
404   LLVMContext C;
405   std::unique_ptr<Module> M = makeLLVMModule(C,
406                                              R"IR(
407 declare void @might_throw()
408 
409 define internal i32 @callee() personality i32 (...)* @__gxx_personality_v0 {
410 entry:
411   invoke void @might_throw()
412       to label %cont unwind label %exc
413 
414 cont:
415   ret i32 0
416 
417 exc:
418   %exn = landingpad {i8*, i32}
419          cleanup
420   resume { i8*, i32 } %exn
421 }
422 
423 define i32 @caller() personality i32 (...)* @__gxx_personality_v0 {
424 entry:
425   %X = invoke i32 @callee()
426            to label %cont unwind label %Handler
427 
428 cont:
429   ret i32 %X
430 
431 Handler:
432   %exn = landingpad {i8*, i32}
433          cleanup
434   ret i32 1
435 }
436 
437 declare i32 @__gxx_personality_v0(...)
438 )IR");
439 
440   Function *F1 = M->getFunction("caller");
441   CallBase* CB = findCall(*F1);
442   EXPECT_NE(CB, nullptr);
443 
444   auto FPI = buildFPI(*F1);
445   FunctionPropertiesUpdater FPU(FPI, *CB);
446   InlineFunctionInfo IFI;
447   auto IR = llvm::InlineFunction(*CB, IFI);
448   EXPECT_TRUE(IR.isSuccess());
449   invalidate(*F1);
450   EXPECT_TRUE(FPU.finishAndTest(FAM));
451   EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size() - 1);
452   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
453             F1->getInstructionCount() - 2);
454   EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));
455 }
456 
457 TEST_F(FunctionPropertiesAnalysisTest, Rethrow) {
458   LLVMContext C;
459   std::unique_ptr<Module> M = makeLLVMModule(C,
460                                              R"IR(
461 declare void @might_throw()
462 
463 define internal i32 @callee() personality i32 (...)* @__gxx_personality_v0 {
464 entry:
465   invoke void @might_throw()
466       to label %cont unwind label %exc
467 
468 cont:
469   ret i32 0
470 
471 exc:
472   %exn = landingpad {i8*, i32}
473          cleanup
474   resume { i8*, i32 } %exn
475 }
476 
477 define i32 @caller() personality i32 (...)* @__gxx_personality_v0 {
478 entry:
479   %X = invoke i32 @callee()
480            to label %cont unwind label %Handler
481 
482 cont:
483   ret i32 %X
484 
485 Handler:
486   %exn = landingpad {i8*, i32}
487          cleanup
488   ret i32 1
489 }
490 
491 declare i32 @__gxx_personality_v0(...)
492 )IR");
493 
494   Function *F1 = M->getFunction("caller");
495   CallBase* CB = findCall(*F1);
496   EXPECT_NE(CB, nullptr);
497 
498   auto FPI = buildFPI(*F1);
499   FunctionPropertiesUpdater FPU(FPI, *CB);
500   InlineFunctionInfo IFI;
501   auto IR = llvm::InlineFunction(*CB, IFI);
502   EXPECT_TRUE(IR.isSuccess());
503   invalidate(*F1);
504   EXPECT_TRUE(FPU.finishAndTest(FAM));
505   EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size() - 1);
506   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
507             F1->getInstructionCount() - 2);
508   EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));
509 }
510 
511 TEST_F(FunctionPropertiesAnalysisTest, LPadChanges) {
512   LLVMContext C;
513   std::unique_ptr<Module> M = makeLLVMModule(C,
514                                              R"IR(
515 declare void @external_func()
516 
517 @exception_type1 = external global i8
518 @exception_type2 = external global i8
519 
520 
521 define internal void @inner() personality i8* null {
522   invoke void @external_func()
523       to label %cont unwind label %lpad
524 cont:
525   ret void
526 lpad:
527   %lp = landingpad i32
528       catch i8* @exception_type1
529   resume i32 %lp
530 }
531 
532 define void @outer() personality i8* null {
533   invoke void @inner()
534       to label %cont unwind label %lpad
535 cont:
536   ret void
537 lpad:
538   %lp = landingpad i32
539       cleanup
540       catch i8* @exception_type2
541   resume i32 %lp
542 }
543 
544 )IR");
545 
546   Function *F1 = M->getFunction("outer");
547   CallBase* CB = findCall(*F1);
548   EXPECT_NE(CB, nullptr);
549 
550   auto FPI = buildFPI(*F1);
551   FunctionPropertiesUpdater FPU(FPI, *CB);
552   InlineFunctionInfo IFI;
553   auto IR = llvm::InlineFunction(*CB, IFI);
554   EXPECT_TRUE(IR.isSuccess());
555   invalidate(*F1);
556   EXPECT_TRUE(FPU.finishAndTest(FAM));
557   EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size() - 1);
558   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
559             F1->getInstructionCount() - 2);
560   EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));
561 }
562 
563 TEST_F(FunctionPropertiesAnalysisTest, LPadChangesConditional) {
564   LLVMContext C;
565   std::unique_ptr<Module> M = makeLLVMModule(C,
566                                              R"IR(
567 declare void @external_func()
568 
569 @exception_type1 = external global i8
570 @exception_type2 = external global i8
571 
572 
573 define internal void @inner() personality i8* null {
574   invoke void @external_func()
575       to label %cont unwind label %lpad
576 cont:
577   ret void
578 lpad:
579   %lp = landingpad i32
580       catch i8* @exception_type1
581   resume i32 %lp
582 }
583 
584 define void @outer(i32 %a) personality i8* null {
585 entry:
586   %i = icmp slt i32 %a, 0
587   br i1 %i, label %if.then, label %cont
588 if.then:
589   invoke void @inner()
590       to label %cont unwind label %lpad
591 cont:
592   ret void
593 lpad:
594   %lp = landingpad i32
595       cleanup
596       catch i8* @exception_type2
597   resume i32 %lp
598 }
599 
600 )IR");
601 
602   Function *F1 = M->getFunction("outer");
603   CallBase* CB = findCall(*F1);
604   EXPECT_NE(CB, nullptr);
605 
606   auto FPI = buildFPI(*F1);
607   FunctionPropertiesUpdater FPU(FPI, *CB);
608   InlineFunctionInfo IFI;
609   auto IR = llvm::InlineFunction(*CB, IFI);
610   EXPECT_TRUE(IR.isSuccess());
611   invalidate(*F1);
612   EXPECT_TRUE(FPU.finishAndTest(FAM));
613   EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size() - 1);
614   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
615             F1->getInstructionCount() - 2);
616   EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));
617 }
618 
619 TEST_F(FunctionPropertiesAnalysisTest, InlineSameLoopBB) {
620   LLVMContext C;
621   std::unique_ptr<Module> M = makeLLVMModule(C,
622                                              R"IR(
623 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
624 target triple = "x86_64-pc-linux-gnu"
625 
626 declare i32 @a()
627 declare i32 @b()
628 
629 define i32 @f1(i32 %a) {
630 entry:
631   br label %loop
632 loop:
633   %i = call i32 @f2(i32 %a)
634   %c = icmp slt i32 %i, %a
635   br i1 %c, label %loop, label %end
636 end:
637   %r = phi i32 [%i, %loop], [%a, %entry]
638   ret i32 %r
639 }
640 
641 define i32 @f2(i32 %a) {
642   %cnd = icmp slt i32 %a, 0
643   br i1 %cnd, label %then, label %else
644 then:
645   %r1 = call i32 @a()
646   br label %end
647 else:
648   %r2 = call i32 @b()
649   br label %end
650 end:
651   %r = phi i32 [%r1, %then], [%r2, %else]
652   ret i32 %r
653 }
654 )IR");
655 
656   Function *F1 = M->getFunction("f1");
657   CallBase *CB = findCall(*F1);
658   EXPECT_NE(CB, nullptr);
659 
660   FunctionPropertiesInfo ExpectedInitial;
661   ExpectedInitial.BasicBlockCount = 3;
662   ExpectedInitial.TotalInstructionCount = 6;
663   ExpectedInitial.BlocksReachedFromConditionalInstruction = 2;
664   ExpectedInitial.Uses = 1;
665   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
666   ExpectedInitial.MaxLoopDepth = 1;
667   ExpectedInitial.TopLevelLoopCount = 1;
668 
669   FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;
670   ExpectedFinal.BasicBlockCount = 6;
671   ExpectedFinal.DirectCallsToDefinedFunctions = 0;
672   ExpectedFinal.BlocksReachedFromConditionalInstruction = 4;
673   ExpectedFinal.TotalInstructionCount = 12;
674 
675   auto FPI = buildFPI(*F1);
676   EXPECT_EQ(FPI, ExpectedInitial);
677 
678   FunctionPropertiesUpdater FPU(FPI, *CB);
679   InlineFunctionInfo IFI;
680   auto IR = llvm::InlineFunction(*CB, IFI);
681   EXPECT_TRUE(IR.isSuccess());
682   invalidate(*F1);
683   EXPECT_TRUE(FPU.finishAndTest(FAM));
684   EXPECT_EQ(FPI, ExpectedFinal);
685 }
686 
687 TEST_F(FunctionPropertiesAnalysisTest, Unreachable) {
688   LLVMContext C;
689   std::unique_ptr<Module> M = makeLLVMModule(C,
690                                              R"IR(
691 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
692 target triple = "x86_64-pc-linux-gnu"
693 
694 define i64 @f1(i32 noundef %value) {
695 entry:
696   br i1 true, label %cond.true, label %cond.false
697 
698 cond.true:                                        ; preds = %entry
699   %conv2 = sext i32 %value to i64
700   br label %cond.end
701 
702 cond.false:                                       ; preds = %entry
703   %call3 = call noundef i64 @f2()
704   br label %extra
705 
706 extra:
707   br label %extra2
708 
709 extra2:
710   br label %cond.end
711 
712 cond.end:                                         ; preds = %cond.false, %cond.true
713   %cond = phi i64 [ %conv2, %cond.true ], [ %call3, %extra ]
714   ret i64 %cond
715 }
716 
717 define i64 @f2() {
718 entry:
719   tail call void @llvm.trap()
720   unreachable
721 }
722 
723 declare void @llvm.trap()
724 )IR");
725 
726   Function *F1 = M->getFunction("f1");
727   CallBase *CB = findCall(*F1);
728   EXPECT_NE(CB, nullptr);
729 
730   FunctionPropertiesInfo ExpectedInitial;
731   ExpectedInitial.BasicBlockCount = 6;
732   ExpectedInitial.TotalInstructionCount = 9;
733   ExpectedInitial.BlocksReachedFromConditionalInstruction = 2;
734   ExpectedInitial.Uses = 1;
735   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
736 
737   FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;
738   ExpectedFinal.BasicBlockCount = 4;
739   ExpectedFinal.DirectCallsToDefinedFunctions = 0;
740   ExpectedFinal.TotalInstructionCount = 7;
741 
742   auto FPI = buildFPI(*F1);
743   EXPECT_EQ(FPI, ExpectedInitial);
744 
745   FunctionPropertiesUpdater FPU(FPI, *CB);
746   InlineFunctionInfo IFI;
747   auto IR = llvm::InlineFunction(*CB, IFI);
748   EXPECT_TRUE(IR.isSuccess());
749   invalidate(*F1);
750   EXPECT_TRUE(FPU.finishAndTest(FAM));
751   EXPECT_EQ(FPI, ExpectedFinal);
752 }
753 
754 TEST_F(FunctionPropertiesAnalysisTest, InvokeSkipLP) {
755   LLVMContext C;
756   std::unique_ptr<Module> M = makeLLVMModule(C,
757                                              R"IR(
758 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
759 target triple = "x86_64-pc-linux-gnu"
760 
761 define i64 @f1(i32 noundef %value) {
762 entry:
763   invoke fastcc void @f2() to label %cont unwind label %lpad
764 cont:
765   ret i64 1
766 lpad:
767   %lp = landingpad i32 cleanup
768   br label %ehcleanup
769 ehcleanup:
770   resume i32 0
771 }
772 define void @f2() {
773   invoke noundef void @f3() to label %exit unwind label %lpad
774 exit:
775   ret void
776 lpad:
777   %lp = landingpad i32 cleanup
778   resume i32 %lp
779 }
780 declare void @f3()
781 )IR");
782 
783   // The outcome of inlining will be that lpad becomes unreachable. The landing
784   // pad of the invoke inherited from f2 will land on a new bb which will branch
785   // to a bb containing the body of lpad.
786   Function *F1 = M->getFunction("f1");
787   CallBase *CB = findCall(*F1);
788   EXPECT_NE(CB, nullptr);
789 
790   FunctionPropertiesInfo ExpectedInitial;
791   ExpectedInitial.BasicBlockCount = 4;
792   ExpectedInitial.TotalInstructionCount = 5;
793   ExpectedInitial.BlocksReachedFromConditionalInstruction = 0;
794   ExpectedInitial.Uses = 1;
795   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
796 
797   FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;
798   ExpectedFinal.BasicBlockCount = 6;
799   ExpectedFinal.DirectCallsToDefinedFunctions = 0;
800   ExpectedFinal.TotalInstructionCount = 8;
801 
802   auto FPI = buildFPI(*F1);
803   EXPECT_EQ(FPI, ExpectedInitial);
804 
805   FunctionPropertiesUpdater FPU(FPI, *CB);
806   InlineFunctionInfo IFI;
807   auto IR = llvm::InlineFunction(*CB, IFI);
808   EXPECT_TRUE(IR.isSuccess());
809   invalidate(*F1);
810   EXPECT_TRUE(FPU.finishAndTest(FAM));
811   EXPECT_EQ(FPI, ExpectedFinal);
812 }
813 
814 TEST_F(FunctionPropertiesAnalysisTest, DetailedOperandCount) {
815   LLVMContext C;
816   std::unique_ptr<Module> M = makeLLVMModule(C,
817                                              R"IR(
818 @a = global i64 1
819 
820 define i64 @f1(i64 %e) {
821 	%b = load i64, i64* @a
822   %c = add i64 %b, 2
823   %d = call i64 asm "mov $1,$0", "=r,r" (i64 %c)
824 	%f = add i64 %d, %e
825 	ret i64 %f
826 }
827 )IR");
828 
829   Function *F1 = M->getFunction("f1");
830   EnableDetailedFunctionProperties.setValue(true);
831   FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);
832   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithSingleSuccessor, 0);
833   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithTwoSuccessors, 0);
834   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithMoreThanTwoSuccessors, 0);
835   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithSinglePredecessor, 0);
836   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithTwoPredecessors, 0);
837   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithMoreThanTwoPredecessors, 0);
838   EXPECT_EQ(DetailedF1Properties.BigBasicBlocks, 0);
839   EXPECT_EQ(DetailedF1Properties.MediumBasicBlocks, 0);
840   EXPECT_EQ(DetailedF1Properties.SmallBasicBlocks, 1);
841   EXPECT_EQ(DetailedF1Properties.CastInstructionCount, 0);
842   EXPECT_EQ(DetailedF1Properties.FloatingPointInstructionCount, 0);
843   EXPECT_EQ(DetailedF1Properties.IntegerInstructionCount, 4);
844   EXPECT_EQ(DetailedF1Properties.ConstantIntOperandCount, 1);
845   EXPECT_EQ(DetailedF1Properties.ConstantFPOperandCount, 0);
846   EXPECT_EQ(DetailedF1Properties.ConstantOperandCount, 0);
847   EXPECT_EQ(DetailedF1Properties.InstructionOperandCount, 4);
848   EXPECT_EQ(DetailedF1Properties.BasicBlockOperandCount, 0);
849   EXPECT_EQ(DetailedF1Properties.GlobalValueOperandCount, 1);
850   EXPECT_EQ(DetailedF1Properties.InlineAsmOperandCount, 1);
851   EXPECT_EQ(DetailedF1Properties.ArgumentOperandCount, 1);
852   EXPECT_EQ(DetailedF1Properties.UnknownOperandCount, 0);
853   EnableDetailedFunctionProperties.setValue(false);
854 }
855 } // end anonymous namespace
856