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