xref: /llvm-project/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp (revision 22a1f998f70f4217c9f4f2e820d0c86717d1a3c3)
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),
329             F1->getBasicBlockList().size());
330   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
331             F1->getInstructionCount());
332 }
333 
334 TEST_F(FunctionPropertiesAnalysisTest, InvokeUnreachableHandler) {
335   LLVMContext C;
336   std::unique_ptr<Module> M = makeLLVMModule(C,
337                                              R"IR(
338 declare void @might_throw()
339 
340 define internal i32 @callee() personality i32 (...)* @__gxx_personality_v0 {
341 entry:
342   invoke void @might_throw()
343       to label %cont unwind label %exc
344 
345 cont:
346   ret i32 0
347 
348 exc:
349   %exn = landingpad {i8*, i32}
350          cleanup
351   resume { i8*, i32 } %exn
352 }
353 
354 define i32 @caller() personality i32 (...)* @__gxx_personality_v0 {
355 entry:
356   %X = invoke i32 @callee()
357            to label %cont unwind label %Handler
358 
359 cont:
360   ret i32 %X
361 
362 Handler:
363   %exn = landingpad {i8*, i32}
364          cleanup
365   ret i32 1
366 }
367 
368 declare i32 @__gxx_personality_v0(...)
369 )IR");
370 
371   Function *F1 = M->getFunction("caller");
372   CallBase* CB = findCall(*F1);
373   EXPECT_NE(CB, nullptr);
374 
375   auto FPI = buildFPI(*F1);
376   FunctionPropertiesUpdater FPU(FPI, *CB);
377   InlineFunctionInfo IFI;
378   auto IR = llvm::InlineFunction(*CB, IFI);
379   EXPECT_TRUE(IR.isSuccess());
380   invalidate(*F1);
381   FPU.finish(FAM);
382   EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount),
383             F1->getBasicBlockList().size() - 1);
384   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
385             F1->getInstructionCount() - 2);
386   EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));
387 }
388 
389 TEST_F(FunctionPropertiesAnalysisTest, Rethrow) {
390   LLVMContext C;
391   std::unique_ptr<Module> M = makeLLVMModule(C,
392                                              R"IR(
393 declare void @might_throw()
394 
395 define internal i32 @callee() personality i32 (...)* @__gxx_personality_v0 {
396 entry:
397   invoke void @might_throw()
398       to label %cont unwind label %exc
399 
400 cont:
401   ret i32 0
402 
403 exc:
404   %exn = landingpad {i8*, i32}
405          cleanup
406   resume { i8*, i32 } %exn
407 }
408 
409 define i32 @caller() personality i32 (...)* @__gxx_personality_v0 {
410 entry:
411   %X = invoke i32 @callee()
412            to label %cont unwind label %Handler
413 
414 cont:
415   ret i32 %X
416 
417 Handler:
418   %exn = landingpad {i8*, i32}
419          cleanup
420   ret i32 1
421 }
422 
423 declare i32 @__gxx_personality_v0(...)
424 )IR");
425 
426   Function *F1 = M->getFunction("caller");
427   CallBase* CB = findCall(*F1);
428   EXPECT_NE(CB, nullptr);
429 
430   auto FPI = buildFPI(*F1);
431   FunctionPropertiesUpdater FPU(FPI, *CB);
432   InlineFunctionInfo IFI;
433   auto IR = llvm::InlineFunction(*CB, IFI);
434   EXPECT_TRUE(IR.isSuccess());
435   invalidate(*F1);
436   FPU.finish(FAM);
437   EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount),
438             F1->getBasicBlockList().size() - 1);
439   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
440             F1->getInstructionCount() - 2);
441   EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));
442 }
443 
444 TEST_F(FunctionPropertiesAnalysisTest, LPadChanges) {
445   LLVMContext C;
446   std::unique_ptr<Module> M = makeLLVMModule(C,
447                                              R"IR(
448 declare void @external_func()
449 
450 @exception_type1 = external global i8
451 @exception_type2 = external global i8
452 
453 
454 define internal void @inner() personality i8* null {
455   invoke void @external_func()
456       to label %cont unwind label %lpad
457 cont:
458   ret void
459 lpad:
460   %lp = landingpad i32
461       catch i8* @exception_type1
462   resume i32 %lp
463 }
464 
465 define void @outer() personality i8* null {
466   invoke void @inner()
467       to label %cont unwind label %lpad
468 cont:
469   ret void
470 lpad:
471   %lp = landingpad i32
472       cleanup
473       catch i8* @exception_type2
474   resume i32 %lp
475 }
476 
477 )IR");
478 
479   Function *F1 = M->getFunction("outer");
480   CallBase* CB = findCall(*F1);
481   EXPECT_NE(CB, nullptr);
482 
483   auto FPI = buildFPI(*F1);
484   FunctionPropertiesUpdater FPU(FPI, *CB);
485   InlineFunctionInfo IFI;
486   auto IR = llvm::InlineFunction(*CB, IFI);
487   EXPECT_TRUE(IR.isSuccess());
488   invalidate(*F1);
489   FPU.finish(FAM);
490   EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount),
491             F1->getBasicBlockList().size() - 1);
492   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
493             F1->getInstructionCount() - 2);
494   EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));
495 }
496 
497 TEST_F(FunctionPropertiesAnalysisTest, LPadChangesConditional) {
498   LLVMContext C;
499   std::unique_ptr<Module> M = makeLLVMModule(C,
500                                              R"IR(
501 declare void @external_func()
502 
503 @exception_type1 = external global i8
504 @exception_type2 = external global i8
505 
506 
507 define internal void @inner() personality i8* null {
508   invoke void @external_func()
509       to label %cont unwind label %lpad
510 cont:
511   ret void
512 lpad:
513   %lp = landingpad i32
514       catch i8* @exception_type1
515   resume i32 %lp
516 }
517 
518 define void @outer(i32 %a) personality i8* null {
519 entry:
520   %i = icmp slt i32 %a, 0
521   br i1 %i, label %if.then, label %cont
522 if.then:
523   invoke void @inner()
524       to label %cont unwind label %lpad
525 cont:
526   ret void
527 lpad:
528   %lp = landingpad i32
529       cleanup
530       catch i8* @exception_type2
531   resume i32 %lp
532 }
533 
534 )IR");
535 
536   Function *F1 = M->getFunction("outer");
537   CallBase* CB = findCall(*F1);
538   EXPECT_NE(CB, nullptr);
539 
540   auto FPI = buildFPI(*F1);
541   FunctionPropertiesUpdater FPU(FPI, *CB);
542   InlineFunctionInfo IFI;
543   auto IR = llvm::InlineFunction(*CB, IFI);
544   EXPECT_TRUE(IR.isSuccess());
545   invalidate(*F1);
546   FPU.finish(FAM);
547   EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount),
548             F1->getBasicBlockList().size() - 1);
549   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
550             F1->getInstructionCount() - 2);
551   EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));
552 }
553 
554 TEST_F(FunctionPropertiesAnalysisTest, InlineSameLoopBB) {
555   LLVMContext C;
556   std::unique_ptr<Module> M = makeLLVMModule(C,
557                                              R"IR(
558 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
559 target triple = "x86_64-pc-linux-gnu"
560 
561 declare i32 @a()
562 declare i32 @b()
563 
564 define i32 @f1(i32 %a) {
565 entry:
566   br label %loop
567 loop:
568   %i = call i32 @f2(i32 %a)
569   %c = icmp slt i32 %i, %a
570   br i1 %c, label %loop, label %end
571 end:
572   %r = phi i32 [%i, %loop], [%a, %entry]
573   ret i32 %r
574 }
575 
576 define i32 @f2(i32 %a) {
577   %cnd = icmp slt i32 %a, 0
578   br i1 %cnd, label %then, label %else
579 then:
580   %r1 = call i32 @a()
581   br label %end
582 else:
583   %r2 = call i32 @b()
584   br label %end
585 end:
586   %r = phi i32 [%r1, %then], [%r2, %else]
587   ret i32 %r
588 }
589 )IR");
590 
591   Function *F1 = M->getFunction("f1");
592   CallBase *CB = findCall(*F1);
593   EXPECT_NE(CB, nullptr);
594 
595   FunctionPropertiesInfo ExpectedInitial;
596   ExpectedInitial.BasicBlockCount = 3;
597   ExpectedInitial.TotalInstructionCount = 6;
598   ExpectedInitial.BlocksReachedFromConditionalInstruction = 2;
599   ExpectedInitial.Uses = 1;
600   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
601   ExpectedInitial.MaxLoopDepth = 1;
602   ExpectedInitial.TopLevelLoopCount = 1;
603 
604   FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;
605   ExpectedFinal.BasicBlockCount = 6;
606   ExpectedFinal.DirectCallsToDefinedFunctions = 0;
607   ExpectedFinal.BlocksReachedFromConditionalInstruction = 4;
608   ExpectedFinal.TotalInstructionCount = 12;
609 
610   auto FPI = buildFPI(*F1);
611   EXPECT_EQ(FPI, ExpectedInitial);
612 
613   FunctionPropertiesUpdater FPU(FPI, *CB);
614   InlineFunctionInfo IFI;
615   auto IR = llvm::InlineFunction(*CB, IFI);
616   EXPECT_TRUE(IR.isSuccess());
617   invalidate(*F1);
618   FPU.finish(FAM);
619   EXPECT_EQ(FPI, ExpectedFinal);
620 }
621 
622 TEST_F(FunctionPropertiesAnalysisTest, Unreachable) {
623   LLVMContext C;
624   std::unique_ptr<Module> M = makeLLVMModule(C,
625                                              R"IR(
626 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
627 target triple = "x86_64-pc-linux-gnu"
628 
629 define i64 @f1(i32 noundef %value) {
630 entry:
631   br i1 true, label %cond.true, label %cond.false
632 
633 cond.true:                                        ; preds = %entry
634   %conv2 = sext i32 %value to i64
635   br label %cond.end
636 
637 cond.false:                                       ; preds = %entry
638   %call3 = call noundef i64 @f2()
639   br label %cond.end
640 
641 cond.end:                                         ; preds = %cond.false, %cond.true
642   %cond = phi i64 [ %conv2, %cond.true ], [ %call3, %cond.false ]
643   ret i64 %cond
644 }
645 
646 define i64 @f2() {
647 entry:
648   tail call void @llvm.trap()
649   unreachable
650 }
651 
652 declare void @llvm.trap()
653 )IR");
654 
655   Function *F1 = M->getFunction("f1");
656   CallBase *CB = findCall(*F1);
657   EXPECT_NE(CB, nullptr);
658 
659   FunctionPropertiesInfo ExpectedInitial;
660   ExpectedInitial.BasicBlockCount = 4;
661   ExpectedInitial.TotalInstructionCount = 7;
662   ExpectedInitial.BlocksReachedFromConditionalInstruction = 2;
663   ExpectedInitial.Uses = 1;
664   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
665 
666   FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;
667   ExpectedFinal.BasicBlockCount = 4;
668   ExpectedFinal.DirectCallsToDefinedFunctions = 0;
669   ExpectedFinal.TotalInstructionCount = 7;
670 
671   auto FPI = buildFPI(*F1);
672   EXPECT_EQ(FPI, ExpectedInitial);
673 
674   FunctionPropertiesUpdater FPU(FPI, *CB);
675   InlineFunctionInfo IFI;
676   auto IR = llvm::InlineFunction(*CB, IFI);
677   EXPECT_TRUE(IR.isSuccess());
678   invalidate(*F1);
679   FPU.finish(FAM);
680   EXPECT_EQ(FPI, ExpectedFinal);
681 }
682 
683 } // end anonymous namespace
684