xref: /llvm-project/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp (revision 1991aa6b48845f31ff4e69a960b04086ff68ce3e)
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/Analysis/AliasAnalysis.h"
11 #include "llvm/Analysis/LoopInfo.h"
12 #include "llvm/AsmParser/Parser.h"
13 #include "llvm/IR/Dominators.h"
14 #include "llvm/IR/Instructions.h"
15 #include "llvm/IR/LLVMContext.h"
16 #include "llvm/IR/Module.h"
17 #include "llvm/IR/PassManager.h"
18 #include "llvm/Passes/PassBuilder.h"
19 #include "llvm/Passes/StandardInstrumentations.h"
20 #include "llvm/Support/SourceMgr.h"
21 #include "llvm/Transforms/Utils/Cloning.h"
22 #include "gtest/gtest.h"
23 #include <cstring>
24 
25 using namespace llvm;
26 
27 namespace llvm {
28 extern cl::opt<bool> EnableDetailedFunctionProperties;
29 extern cl::opt<bool> BigBasicBlockInstructionThreshold;
30 extern cl::opt<bool> MediumBasicBlockInstrutionThreshold;
31 } // namespace llvm
32 
33 namespace {
34 
35 class FunctionPropertiesAnalysisTest : public testing::Test {
36 public:
37   FunctionPropertiesAnalysisTest() {
38     FAM.registerPass([&] { return DominatorTreeAnalysis(); });
39     FAM.registerPass([&] { return LoopAnalysis(); });
40     FAM.registerPass([&] { return PassInstrumentationAnalysis(); });
41   }
42 
43 protected:
44   std::unique_ptr<DominatorTree> DT;
45   std::unique_ptr<LoopInfo> LI;
46   FunctionAnalysisManager FAM;
47 
48   FunctionPropertiesInfo buildFPI(Function &F) {
49     return FunctionPropertiesInfo::getFunctionPropertiesInfo(F, FAM);
50   }
51 
52   void invalidate(Function &F) {
53     PreservedAnalyses PA = PreservedAnalyses::none();
54     FAM.invalidate(F, PA);
55   }
56 
57   std::unique_ptr<Module> makeLLVMModule(LLVMContext &C, const char *IR) {
58     SMDiagnostic Err;
59     std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
60     if (!Mod)
61       Err.print("MLAnalysisTests", errs());
62     return Mod;
63   }
64 
65   CallBase* findCall(Function& F, const char* Name = nullptr) {
66     for (auto &BB : F)
67       for (auto &I : BB )
68         if (auto *CB = dyn_cast<CallBase>(&I))
69           if (!Name || CB->getName() == Name)
70             return CB;
71     return nullptr;
72   }
73 };
74 
75 TEST_F(FunctionPropertiesAnalysisTest, BasicTest) {
76   LLVMContext C;
77   std::unique_ptr<Module> M = makeLLVMModule(C,
78                                              R"IR(
79 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
80 target triple = "x86_64-pc-linux-gnu"
81 declare i32 @f1(i32)
82 declare i32 @f2(i32)
83 define i32 @branches(i32) {
84   %cond = icmp slt i32 %0, 3
85   br i1 %cond, label %then, label %else
86 then:
87   %ret.1 = call i32 @f1(i32 %0)
88   br label %last.block
89 else:
90   %ret.2 = call i32 @f2(i32 %0)
91   br label %last.block
92 last.block:
93   %ret = phi i32 [%ret.1, %then], [%ret.2, %else]
94   ret i32 %ret
95 }
96 define internal i32 @top() {
97   %1 = call i32 @branches(i32 2)
98   %2 = call i32 @f1(i32 %1)
99   ret i32 %2
100 }
101 )IR");
102 
103   Function *BranchesFunction = M->getFunction("branches");
104   FunctionPropertiesInfo BranchesFeatures = buildFPI(*BranchesFunction);
105   EXPECT_EQ(BranchesFeatures.BasicBlockCount, 4);
106   EXPECT_EQ(BranchesFeatures.BlocksReachedFromConditionalInstruction, 2);
107   // 2 Users: top is one. The other is added because @branches is not internal,
108   // so it may have external callers.
109   EXPECT_EQ(BranchesFeatures.Uses, 2);
110   EXPECT_EQ(BranchesFeatures.DirectCallsToDefinedFunctions, 0);
111   EXPECT_EQ(BranchesFeatures.LoadInstCount, 0);
112   EXPECT_EQ(BranchesFeatures.StoreInstCount, 0);
113   EXPECT_EQ(BranchesFeatures.MaxLoopDepth, 0);
114   EXPECT_EQ(BranchesFeatures.TopLevelLoopCount, 0);
115 
116   Function *TopFunction = M->getFunction("top");
117   FunctionPropertiesInfo TopFeatures = buildFPI(*TopFunction);
118   EXPECT_EQ(TopFeatures.BasicBlockCount, 1);
119   EXPECT_EQ(TopFeatures.BlocksReachedFromConditionalInstruction, 0);
120   EXPECT_EQ(TopFeatures.Uses, 0);
121   EXPECT_EQ(TopFeatures.DirectCallsToDefinedFunctions, 1);
122   EXPECT_EQ(BranchesFeatures.LoadInstCount, 0);
123   EXPECT_EQ(BranchesFeatures.StoreInstCount, 0);
124   EXPECT_EQ(BranchesFeatures.MaxLoopDepth, 0);
125   EXPECT_EQ(BranchesFeatures.TopLevelLoopCount, 0);
126 
127   EnableDetailedFunctionProperties.setValue(true);
128   FunctionPropertiesInfo DetailedBranchesFeatures = buildFPI(*BranchesFunction);
129   EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithSingleSuccessor, 2);
130   EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithTwoSuccessors, 1);
131   EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithMoreThanTwoSuccessors, 0);
132   EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithSinglePredecessor, 2);
133   EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithTwoPredecessors, 1);
134   EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithMoreThanTwoPredecessors, 0);
135   EXPECT_EQ(DetailedBranchesFeatures.BigBasicBlocks, 0);
136   EXPECT_EQ(DetailedBranchesFeatures.MediumBasicBlocks, 0);
137   EXPECT_EQ(DetailedBranchesFeatures.SmallBasicBlocks, 4);
138   EXPECT_EQ(DetailedBranchesFeatures.CastInstructionCount, 0);
139   EXPECT_EQ(DetailedBranchesFeatures.FloatingPointInstructionCount, 0);
140   EXPECT_EQ(DetailedBranchesFeatures.IntegerInstructionCount, 4);
141   EXPECT_EQ(DetailedBranchesFeatures.ConstantIntOperandCount, 1);
142   EXPECT_EQ(DetailedBranchesFeatures.ConstantFPOperandCount, 0);
143   EXPECT_EQ(DetailedBranchesFeatures.ConstantOperandCount, 0);
144   EXPECT_EQ(DetailedBranchesFeatures.InstructionOperandCount, 4);
145   EXPECT_EQ(DetailedBranchesFeatures.BasicBlockOperandCount, 4);
146   EXPECT_EQ(DetailedBranchesFeatures.GlobalValueOperandCount, 2);
147   EXPECT_EQ(DetailedBranchesFeatures.InlineAsmOperandCount, 0);
148   EXPECT_EQ(DetailedBranchesFeatures.ArgumentOperandCount, 3);
149   EXPECT_EQ(DetailedBranchesFeatures.UnknownOperandCount, 0);
150   EXPECT_EQ(DetailedBranchesFeatures.CriticalEdgeCount, 0);
151   EXPECT_EQ(DetailedBranchesFeatures.ControlFlowEdgeCount, 4);
152   EXPECT_EQ(DetailedBranchesFeatures.UnconditionalBranchCount, 2);
153   EXPECT_EQ(DetailedBranchesFeatures.IntrinsicCount, 0);
154   EXPECT_EQ(DetailedBranchesFeatures.DirectCallCount, 2);
155   EXPECT_EQ(DetailedBranchesFeatures.IndirectCallCount, 0);
156   EXPECT_EQ(DetailedBranchesFeatures.CallReturnsIntegerCount, 2);
157   EXPECT_EQ(DetailedBranchesFeatures.CallReturnsFloatCount, 0);
158   EXPECT_EQ(DetailedBranchesFeatures.CallReturnsPointerCount, 0);
159   EXPECT_EQ(DetailedBranchesFeatures.CallWithManyArgumentsCount, 0);
160   EXPECT_EQ(DetailedBranchesFeatures.CallWithPointerArgumentCount, 0);
161   EnableDetailedFunctionProperties.setValue(false);
162 }
163 
164 TEST_F(FunctionPropertiesAnalysisTest, DifferentPredecessorSuccessorCounts) {
165   LLVMContext C;
166   std::unique_ptr<Module> M = makeLLVMModule(C,
167                                              R"IR(
168 define i64 @f1() {
169   br i1 0, label %br1, label %finally
170 br1:
171   ret i64 0
172 finally:
173   ret i64 3
174 }
175 )IR");
176 
177   Function *F1 = M->getFunction("f1");
178   EnableDetailedFunctionProperties.setValue(true);
179   FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);
180   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithSingleSuccessor, 0);
181   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithTwoSuccessors, 1);
182   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithMoreThanTwoSuccessors, 0);
183   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithSinglePredecessor, 2);
184   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithTwoPredecessors, 0);
185   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithMoreThanTwoPredecessors, 0);
186   EXPECT_EQ(DetailedF1Properties.BigBasicBlocks, 0);
187   EXPECT_EQ(DetailedF1Properties.MediumBasicBlocks, 0);
188   EXPECT_EQ(DetailedF1Properties.SmallBasicBlocks, 3);
189   EXPECT_EQ(DetailedF1Properties.CastInstructionCount, 0);
190   EXPECT_EQ(DetailedF1Properties.FloatingPointInstructionCount, 0);
191   EXPECT_EQ(DetailedF1Properties.IntegerInstructionCount, 0);
192   EXPECT_EQ(DetailedF1Properties.ConstantIntOperandCount, 3);
193   EXPECT_EQ(DetailedF1Properties.ConstantFPOperandCount, 0);
194   EXPECT_EQ(DetailedF1Properties.ConstantOperandCount, 0);
195   EXPECT_EQ(DetailedF1Properties.InstructionOperandCount, 0);
196   EXPECT_EQ(DetailedF1Properties.BasicBlockOperandCount, 2);
197   EXPECT_EQ(DetailedF1Properties.GlobalValueOperandCount, 0);
198   EXPECT_EQ(DetailedF1Properties.InlineAsmOperandCount, 0);
199   EXPECT_EQ(DetailedF1Properties.ArgumentOperandCount, 0);
200   EXPECT_EQ(DetailedF1Properties.UnknownOperandCount, 0);
201   EXPECT_EQ(DetailedF1Properties.CriticalEdgeCount, 0);
202   EXPECT_EQ(DetailedF1Properties.ControlFlowEdgeCount, 2);
203   EXPECT_EQ(DetailedF1Properties.UnconditionalBranchCount, 0);
204   EXPECT_EQ(DetailedF1Properties.IntrinsicCount, 0);
205   EXPECT_EQ(DetailedF1Properties.DirectCallCount, 0);
206   EXPECT_EQ(DetailedF1Properties.IndirectCallCount, 0);
207   EXPECT_EQ(DetailedF1Properties.CallReturnsIntegerCount, 0);
208   EXPECT_EQ(DetailedF1Properties.CallReturnsFloatCount, 0);
209   EXPECT_EQ(DetailedF1Properties.CallReturnsPointerCount, 0);
210   EXPECT_EQ(DetailedF1Properties.CallWithManyArgumentsCount, 0);
211   EXPECT_EQ(DetailedF1Properties.CallWithPointerArgumentCount, 0);
212   EnableDetailedFunctionProperties.setValue(false);
213 }
214 
215 TEST_F(FunctionPropertiesAnalysisTest, InlineSameBBSimple) {
216   LLVMContext C;
217   std::unique_ptr<Module> M = makeLLVMModule(C,
218                                              R"IR(
219 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
220 target triple = "x86_64-pc-linux-gnu"
221 define i32 @f1(i32 %a) {
222   %b = call i32 @f2(i32 %a)
223   %c = add i32 %b, 2
224   ret i32 %c
225 }
226 
227 define i32 @f2(i32 %a) {
228   %b = add i32 %a, 1
229   ret i32 %b
230 }
231 )IR");
232 
233   Function *F1 = M->getFunction("f1");
234   CallBase* CB = findCall(*F1, "b");
235   EXPECT_NE(CB, nullptr);
236 
237   FunctionPropertiesInfo ExpectedInitial;
238   ExpectedInitial.BasicBlockCount = 1;
239   ExpectedInitial.TotalInstructionCount = 3;
240   ExpectedInitial.Uses = 1;
241   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
242 
243   FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;
244   ExpectedFinal.DirectCallsToDefinedFunctions = 0;
245 
246   auto FPI = buildFPI(*F1);
247   EXPECT_EQ(FPI, ExpectedInitial);
248 
249   FunctionPropertiesUpdater FPU(FPI, *CB);
250   InlineFunctionInfo IFI;
251   auto IR = llvm::InlineFunction(*CB, IFI);
252   EXPECT_TRUE(IR.isSuccess());
253   invalidate(*F1);
254   EXPECT_TRUE(FPU.finishAndTest(FAM));
255   EXPECT_EQ(FPI, ExpectedFinal);
256 }
257 
258 TEST_F(FunctionPropertiesAnalysisTest, InlineSameBBLargerCFG) {
259   LLVMContext C;
260   std::unique_ptr<Module> M = makeLLVMModule(C,
261                                              R"IR(
262 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
263 target triple = "x86_64-pc-linux-gnu"
264 define i32 @f1(i32 %a) {
265 entry:
266   %i = icmp slt i32 %a, 0
267   br i1 %i, label %if.then, label %if.else
268 if.then:
269   %b = call i32 @f2(i32 %a)
270   %c1 = add i32 %b, 2
271   br label %end
272 if.else:
273   %c2 = add i32 %a, 1
274   br label %end
275 end:
276   %ret = phi i32 [%c1, %if.then],[%c2, %if.else]
277   ret i32 %ret
278 }
279 
280 define i32 @f2(i32 %a) {
281   %b = add i32 %a, 1
282   ret i32 %b
283 }
284 )IR");
285 
286   Function *F1 = M->getFunction("f1");
287   CallBase* CB = findCall(*F1, "b");
288   EXPECT_NE(CB, nullptr);
289 
290   FunctionPropertiesInfo ExpectedInitial;
291   ExpectedInitial.BasicBlockCount = 4;
292   ExpectedInitial.BlocksReachedFromConditionalInstruction = 2;
293   ExpectedInitial.TotalInstructionCount = 9;
294   ExpectedInitial.Uses = 1;
295   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
296 
297   FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;
298   ExpectedFinal.DirectCallsToDefinedFunctions = 0;
299 
300   auto FPI = buildFPI(*F1);
301   EXPECT_EQ(FPI, ExpectedInitial);
302 
303   FunctionPropertiesUpdater FPU(FPI, *CB);
304   InlineFunctionInfo IFI;
305   auto IR = llvm::InlineFunction(*CB, IFI);
306   EXPECT_TRUE(IR.isSuccess());
307   invalidate(*F1);
308   EXPECT_TRUE(FPU.finishAndTest(FAM));
309   EXPECT_EQ(FPI, ExpectedFinal);
310 }
311 
312 TEST_F(FunctionPropertiesAnalysisTest, InlineSameBBLoops) {
313   LLVMContext C;
314   std::unique_ptr<Module> M = makeLLVMModule(C,
315                                              R"IR(
316 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
317 target triple = "x86_64-pc-linux-gnu"
318 define i32 @f1(i32 %a) {
319 entry:
320   %i = icmp slt i32 %a, 0
321   br i1 %i, label %if.then, label %if.else
322 if.then:
323   %b = call i32 @f2(i32 %a)
324   %c1 = add i32 %b, 2
325   br label %end
326 if.else:
327   %c2 = add i32 %a, 1
328   br label %end
329 end:
330   %ret = phi i32 [%c1, %if.then],[%c2, %if.else]
331   ret i32 %ret
332 }
333 
334 define i32 @f2(i32 %a) {
335 entry:
336   br label %loop
337 loop:
338   %indvar = phi i32 [%indvar.next, %loop], [0, %entry]
339   %b = add i32 %a, %indvar
340   %indvar.next = add i32 %indvar, 1
341   %cond = icmp slt i32 %indvar.next, %a
342   br i1 %cond, label %loop, label %exit
343 exit:
344   ret i32 %b
345 }
346 )IR");
347 
348   Function *F1 = M->getFunction("f1");
349   CallBase* CB = findCall(*F1, "b");
350   EXPECT_NE(CB, nullptr);
351 
352   FunctionPropertiesInfo ExpectedInitial;
353   ExpectedInitial.BasicBlockCount = 4;
354   ExpectedInitial.BlocksReachedFromConditionalInstruction = 2;
355   ExpectedInitial.TotalInstructionCount = 9;
356   ExpectedInitial.Uses = 1;
357   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
358 
359   FunctionPropertiesInfo ExpectedFinal;
360   ExpectedFinal.BasicBlockCount = 6;
361   ExpectedFinal.BlocksReachedFromConditionalInstruction = 4;
362   ExpectedFinal.Uses = 1;
363   ExpectedFinal.MaxLoopDepth = 1;
364   ExpectedFinal.TopLevelLoopCount = 1;
365   ExpectedFinal.TotalInstructionCount = 14;
366 
367   auto FPI = buildFPI(*F1);
368   EXPECT_EQ(FPI, ExpectedInitial);
369   FunctionPropertiesUpdater FPU(FPI, *CB);
370   InlineFunctionInfo IFI;
371 
372   auto IR = llvm::InlineFunction(*CB, IFI);
373   EXPECT_TRUE(IR.isSuccess());
374   invalidate(*F1);
375   EXPECT_TRUE(FPU.finishAndTest(FAM));
376   EXPECT_EQ(FPI, ExpectedFinal);
377 }
378 
379 TEST_F(FunctionPropertiesAnalysisTest, InvokeSimple) {
380   LLVMContext C;
381   std::unique_ptr<Module> M = makeLLVMModule(C,
382                                              R"IR(
383 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
384 target triple = "x86_64-pc-linux-gnu"
385 declare void @might_throw()
386 
387 define internal void @callee() {
388 entry:
389   call void @might_throw()
390   ret void
391 }
392 
393 define i32 @caller() personality i32 (...)* @__gxx_personality_v0 {
394 entry:
395   invoke void @callee()
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   ret i32 1
405 }
406 
407 declare i32 @__gxx_personality_v0(...)
408 )IR");
409 
410   Function *F1 = M->getFunction("caller");
411   CallBase* CB = findCall(*F1);
412   EXPECT_NE(CB, nullptr);
413 
414   auto FPI = buildFPI(*F1);
415   FunctionPropertiesUpdater FPU(FPI, *CB);
416   InlineFunctionInfo IFI;
417   auto IR = llvm::InlineFunction(*CB, IFI);
418   EXPECT_TRUE(IR.isSuccess());
419   invalidate(*F1);
420   EXPECT_TRUE(FPU.finishAndTest(FAM));
421   EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size());
422   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
423             F1->getInstructionCount());
424 }
425 
426 TEST_F(FunctionPropertiesAnalysisTest, InvokeUnreachableHandler) {
427   LLVMContext C;
428   std::unique_ptr<Module> M = makeLLVMModule(C,
429                                              R"IR(
430 declare void @might_throw()
431 
432 define internal i32 @callee() personality i32 (...)* @__gxx_personality_v0 {
433 entry:
434   invoke void @might_throw()
435       to label %cont unwind label %exc
436 
437 cont:
438   ret i32 0
439 
440 exc:
441   %exn = landingpad {i8*, i32}
442          cleanup
443   resume { i8*, i32 } %exn
444 }
445 
446 define i32 @caller() personality i32 (...)* @__gxx_personality_v0 {
447 entry:
448   %X = invoke i32 @callee()
449            to label %cont unwind label %Handler
450 
451 cont:
452   ret i32 %X
453 
454 Handler:
455   %exn = landingpad {i8*, i32}
456          cleanup
457   ret i32 1
458 }
459 
460 declare i32 @__gxx_personality_v0(...)
461 )IR");
462 
463   Function *F1 = M->getFunction("caller");
464   CallBase* CB = findCall(*F1);
465   EXPECT_NE(CB, nullptr);
466 
467   auto FPI = buildFPI(*F1);
468   FunctionPropertiesUpdater FPU(FPI, *CB);
469   InlineFunctionInfo IFI;
470   auto IR = llvm::InlineFunction(*CB, IFI);
471   EXPECT_TRUE(IR.isSuccess());
472   invalidate(*F1);
473   EXPECT_TRUE(FPU.finishAndTest(FAM));
474   EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size() - 1);
475   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
476             F1->getInstructionCount() - 2);
477   EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));
478 }
479 
480 TEST_F(FunctionPropertiesAnalysisTest, Rethrow) {
481   LLVMContext C;
482   std::unique_ptr<Module> M = makeLLVMModule(C,
483                                              R"IR(
484 declare void @might_throw()
485 
486 define internal i32 @callee() personality i32 (...)* @__gxx_personality_v0 {
487 entry:
488   invoke void @might_throw()
489       to label %cont unwind label %exc
490 
491 cont:
492   ret i32 0
493 
494 exc:
495   %exn = landingpad {i8*, i32}
496          cleanup
497   resume { i8*, i32 } %exn
498 }
499 
500 define i32 @caller() personality i32 (...)* @__gxx_personality_v0 {
501 entry:
502   %X = invoke i32 @callee()
503            to label %cont unwind label %Handler
504 
505 cont:
506   ret i32 %X
507 
508 Handler:
509   %exn = landingpad {i8*, i32}
510          cleanup
511   ret i32 1
512 }
513 
514 declare i32 @__gxx_personality_v0(...)
515 )IR");
516 
517   Function *F1 = M->getFunction("caller");
518   CallBase* CB = findCall(*F1);
519   EXPECT_NE(CB, nullptr);
520 
521   auto FPI = buildFPI(*F1);
522   FunctionPropertiesUpdater FPU(FPI, *CB);
523   InlineFunctionInfo IFI;
524   auto IR = llvm::InlineFunction(*CB, IFI);
525   EXPECT_TRUE(IR.isSuccess());
526   invalidate(*F1);
527   EXPECT_TRUE(FPU.finishAndTest(FAM));
528   EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size() - 1);
529   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
530             F1->getInstructionCount() - 2);
531   EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));
532 }
533 
534 TEST_F(FunctionPropertiesAnalysisTest, LPadChanges) {
535   LLVMContext C;
536   std::unique_ptr<Module> M = makeLLVMModule(C,
537                                              R"IR(
538 declare void @external_func()
539 
540 @exception_type1 = external global i8
541 @exception_type2 = external global i8
542 
543 
544 define internal void @inner() personality i8* null {
545   invoke void @external_func()
546       to label %cont unwind label %lpad
547 cont:
548   ret void
549 lpad:
550   %lp = landingpad i32
551       catch i8* @exception_type1
552   resume i32 %lp
553 }
554 
555 define void @outer() personality i8* null {
556   invoke void @inner()
557       to label %cont unwind label %lpad
558 cont:
559   ret void
560 lpad:
561   %lp = landingpad i32
562       cleanup
563       catch i8* @exception_type2
564   resume i32 %lp
565 }
566 
567 )IR");
568 
569   Function *F1 = M->getFunction("outer");
570   CallBase* CB = findCall(*F1);
571   EXPECT_NE(CB, nullptr);
572 
573   auto FPI = buildFPI(*F1);
574   FunctionPropertiesUpdater FPU(FPI, *CB);
575   InlineFunctionInfo IFI;
576   auto IR = llvm::InlineFunction(*CB, IFI);
577   EXPECT_TRUE(IR.isSuccess());
578   invalidate(*F1);
579   EXPECT_TRUE(FPU.finishAndTest(FAM));
580   EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size() - 1);
581   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
582             F1->getInstructionCount() - 2);
583   EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));
584 }
585 
586 TEST_F(FunctionPropertiesAnalysisTest, LPadChangesConditional) {
587   LLVMContext C;
588   std::unique_ptr<Module> M = makeLLVMModule(C,
589                                              R"IR(
590 declare void @external_func()
591 
592 @exception_type1 = external global i8
593 @exception_type2 = external global i8
594 
595 
596 define internal void @inner() personality i8* null {
597   invoke void @external_func()
598       to label %cont unwind label %lpad
599 cont:
600   ret void
601 lpad:
602   %lp = landingpad i32
603       catch i8* @exception_type1
604   resume i32 %lp
605 }
606 
607 define void @outer(i32 %a) personality i8* null {
608 entry:
609   %i = icmp slt i32 %a, 0
610   br i1 %i, label %if.then, label %cont
611 if.then:
612   invoke void @inner()
613       to label %cont unwind label %lpad
614 cont:
615   ret void
616 lpad:
617   %lp = landingpad i32
618       cleanup
619       catch i8* @exception_type2
620   resume i32 %lp
621 }
622 
623 )IR");
624 
625   Function *F1 = M->getFunction("outer");
626   CallBase* CB = findCall(*F1);
627   EXPECT_NE(CB, nullptr);
628 
629   auto FPI = buildFPI(*F1);
630   FunctionPropertiesUpdater FPU(FPI, *CB);
631   InlineFunctionInfo IFI;
632   auto IR = llvm::InlineFunction(*CB, IFI);
633   EXPECT_TRUE(IR.isSuccess());
634   invalidate(*F1);
635   EXPECT_TRUE(FPU.finishAndTest(FAM));
636   EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size() - 1);
637   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
638             F1->getInstructionCount() - 2);
639   EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));
640 }
641 
642 TEST_F(FunctionPropertiesAnalysisTest, InlineSameLoopBB) {
643   LLVMContext C;
644   std::unique_ptr<Module> M = makeLLVMModule(C,
645                                              R"IR(
646 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
647 target triple = "x86_64-pc-linux-gnu"
648 
649 declare i32 @a()
650 declare i32 @b()
651 
652 define i32 @f1(i32 %a) {
653 entry:
654   br label %loop
655 loop:
656   %i = call i32 @f2(i32 %a)
657   %c = icmp slt i32 %i, %a
658   br i1 %c, label %loop, label %end
659 end:
660   %r = phi i32 [%i, %loop], [%a, %entry]
661   ret i32 %r
662 }
663 
664 define i32 @f2(i32 %a) {
665   %cnd = icmp slt i32 %a, 0
666   br i1 %cnd, label %then, label %else
667 then:
668   %r1 = call i32 @a()
669   br label %end
670 else:
671   %r2 = call i32 @b()
672   br label %end
673 end:
674   %r = phi i32 [%r1, %then], [%r2, %else]
675   ret i32 %r
676 }
677 )IR");
678 
679   Function *F1 = M->getFunction("f1");
680   CallBase *CB = findCall(*F1);
681   EXPECT_NE(CB, nullptr);
682 
683   FunctionPropertiesInfo ExpectedInitial;
684   ExpectedInitial.BasicBlockCount = 3;
685   ExpectedInitial.TotalInstructionCount = 6;
686   ExpectedInitial.BlocksReachedFromConditionalInstruction = 2;
687   ExpectedInitial.Uses = 1;
688   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
689   ExpectedInitial.MaxLoopDepth = 1;
690   ExpectedInitial.TopLevelLoopCount = 1;
691 
692   FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;
693   ExpectedFinal.BasicBlockCount = 6;
694   ExpectedFinal.DirectCallsToDefinedFunctions = 0;
695   ExpectedFinal.BlocksReachedFromConditionalInstruction = 4;
696   ExpectedFinal.TotalInstructionCount = 12;
697 
698   auto FPI = buildFPI(*F1);
699   EXPECT_EQ(FPI, ExpectedInitial);
700 
701   FunctionPropertiesUpdater FPU(FPI, *CB);
702   InlineFunctionInfo IFI;
703   auto IR = llvm::InlineFunction(*CB, IFI);
704   EXPECT_TRUE(IR.isSuccess());
705   invalidate(*F1);
706   EXPECT_TRUE(FPU.finishAndTest(FAM));
707   EXPECT_EQ(FPI, ExpectedFinal);
708 }
709 
710 TEST_F(FunctionPropertiesAnalysisTest, Unreachable) {
711   LLVMContext C;
712   std::unique_ptr<Module> M = makeLLVMModule(C,
713                                              R"IR(
714 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
715 target triple = "x86_64-pc-linux-gnu"
716 
717 define i64 @f1(i32 noundef %value) {
718 entry:
719   br i1 true, label %cond.true, label %cond.false
720 
721 cond.true:                                        ; preds = %entry
722   %conv2 = sext i32 %value to i64
723   br label %cond.end
724 
725 cond.false:                                       ; preds = %entry
726   %call3 = call noundef i64 @f2()
727   br label %extra
728 
729 extra:
730   br label %extra2
731 
732 extra2:
733   br label %cond.end
734 
735 cond.end:                                         ; preds = %cond.false, %cond.true
736   %cond = phi i64 [ %conv2, %cond.true ], [ %call3, %extra ]
737   ret i64 %cond
738 }
739 
740 define i64 @f2() {
741 entry:
742   tail call void @llvm.trap()
743   unreachable
744 }
745 
746 declare void @llvm.trap()
747 )IR");
748 
749   Function *F1 = M->getFunction("f1");
750   CallBase *CB = findCall(*F1);
751   EXPECT_NE(CB, nullptr);
752 
753   FunctionPropertiesInfo ExpectedInitial;
754   ExpectedInitial.BasicBlockCount = 6;
755   ExpectedInitial.TotalInstructionCount = 9;
756   ExpectedInitial.BlocksReachedFromConditionalInstruction = 2;
757   ExpectedInitial.Uses = 1;
758   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
759 
760   FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;
761   ExpectedFinal.BasicBlockCount = 4;
762   ExpectedFinal.DirectCallsToDefinedFunctions = 0;
763   ExpectedFinal.TotalInstructionCount = 7;
764 
765   auto FPI = buildFPI(*F1);
766   EXPECT_EQ(FPI, ExpectedInitial);
767 
768   FunctionPropertiesUpdater FPU(FPI, *CB);
769   InlineFunctionInfo IFI;
770   auto IR = llvm::InlineFunction(*CB, IFI);
771   EXPECT_TRUE(IR.isSuccess());
772   invalidate(*F1);
773   EXPECT_TRUE(FPU.finishAndTest(FAM));
774   EXPECT_EQ(FPI, ExpectedFinal);
775 }
776 
777 TEST_F(FunctionPropertiesAnalysisTest, InvokeSkipLP) {
778   LLVMContext C;
779   std::unique_ptr<Module> M = makeLLVMModule(C,
780                                              R"IR(
781 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
782 target triple = "x86_64-pc-linux-gnu"
783 
784 define i64 @f1(i32 noundef %value) {
785 entry:
786   invoke fastcc void @f2() to label %cont unwind label %lpad
787 cont:
788   ret i64 1
789 lpad:
790   %lp = landingpad i32 cleanup
791   br label %ehcleanup
792 ehcleanup:
793   resume i32 0
794 }
795 define void @f2() {
796   invoke noundef void @f3() to label %exit unwind label %lpad
797 exit:
798   ret void
799 lpad:
800   %lp = landingpad i32 cleanup
801   resume i32 %lp
802 }
803 declare void @f3()
804 )IR");
805 
806   // The outcome of inlining will be that lpad becomes unreachable. The landing
807   // pad of the invoke inherited from f2 will land on a new bb which will branch
808   // to a bb containing the body of lpad.
809   Function *F1 = M->getFunction("f1");
810   CallBase *CB = findCall(*F1);
811   EXPECT_NE(CB, nullptr);
812 
813   FunctionPropertiesInfo ExpectedInitial;
814   ExpectedInitial.BasicBlockCount = 4;
815   ExpectedInitial.TotalInstructionCount = 5;
816   ExpectedInitial.BlocksReachedFromConditionalInstruction = 0;
817   ExpectedInitial.Uses = 1;
818   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
819 
820   FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;
821   ExpectedFinal.BasicBlockCount = 6;
822   ExpectedFinal.DirectCallsToDefinedFunctions = 0;
823   ExpectedFinal.TotalInstructionCount = 8;
824 
825   auto FPI = buildFPI(*F1);
826   EXPECT_EQ(FPI, ExpectedInitial);
827 
828   FunctionPropertiesUpdater FPU(FPI, *CB);
829   InlineFunctionInfo IFI;
830   auto IR = llvm::InlineFunction(*CB, IFI);
831   EXPECT_TRUE(IR.isSuccess());
832   invalidate(*F1);
833   EXPECT_TRUE(FPU.finishAndTest(FAM));
834   EXPECT_EQ(FPI, ExpectedFinal);
835 }
836 
837 TEST_F(FunctionPropertiesAnalysisTest, DetailedOperandCount) {
838   LLVMContext C;
839   std::unique_ptr<Module> M = makeLLVMModule(C,
840                                              R"IR(
841 @a = global i64 1
842 
843 define i64 @f1(i64 %e) {
844 	%b = load i64, i64* @a
845   %c = add i64 %b, 2
846   %d = call i64 asm "mov $1,$0", "=r,r" (i64 %c)
847 	%f = add i64 %d, %e
848 	ret i64 %f
849 }
850 )IR");
851 
852   Function *F1 = M->getFunction("f1");
853   EnableDetailedFunctionProperties.setValue(true);
854   FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);
855   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithSingleSuccessor, 0);
856   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithTwoSuccessors, 0);
857   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithMoreThanTwoSuccessors, 0);
858   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithSinglePredecessor, 0);
859   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithTwoPredecessors, 0);
860   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithMoreThanTwoPredecessors, 0);
861   EXPECT_EQ(DetailedF1Properties.BigBasicBlocks, 0);
862   EXPECT_EQ(DetailedF1Properties.MediumBasicBlocks, 0);
863   EXPECT_EQ(DetailedF1Properties.SmallBasicBlocks, 1);
864   EXPECT_EQ(DetailedF1Properties.CastInstructionCount, 0);
865   EXPECT_EQ(DetailedF1Properties.FloatingPointInstructionCount, 0);
866   EXPECT_EQ(DetailedF1Properties.IntegerInstructionCount, 4);
867   EXPECT_EQ(DetailedF1Properties.ConstantIntOperandCount, 1);
868   EXPECT_EQ(DetailedF1Properties.ConstantFPOperandCount, 0);
869   EXPECT_EQ(DetailedF1Properties.ConstantOperandCount, 0);
870   EXPECT_EQ(DetailedF1Properties.InstructionOperandCount, 4);
871   EXPECT_EQ(DetailedF1Properties.BasicBlockOperandCount, 0);
872   EXPECT_EQ(DetailedF1Properties.GlobalValueOperandCount, 1);
873   EXPECT_EQ(DetailedF1Properties.InlineAsmOperandCount, 1);
874   EXPECT_EQ(DetailedF1Properties.ArgumentOperandCount, 1);
875   EXPECT_EQ(DetailedF1Properties.UnknownOperandCount, 0);
876   EXPECT_EQ(DetailedF1Properties.CriticalEdgeCount, 0);
877   EXPECT_EQ(DetailedF1Properties.ControlFlowEdgeCount, 0);
878   EXPECT_EQ(DetailedF1Properties.UnconditionalBranchCount, 0);
879   EXPECT_EQ(DetailedF1Properties.IntrinsicCount, 0);
880   EXPECT_EQ(DetailedF1Properties.DirectCallCount, 1);
881   EXPECT_EQ(DetailedF1Properties.IndirectCallCount, 0);
882   EXPECT_EQ(DetailedF1Properties.CallReturnsIntegerCount, 1);
883   EXPECT_EQ(DetailedF1Properties.CallReturnsFloatCount, 0);
884   EXPECT_EQ(DetailedF1Properties.CallReturnsPointerCount, 0);
885   EXPECT_EQ(DetailedF1Properties.CallWithManyArgumentsCount, 0);
886   EXPECT_EQ(DetailedF1Properties.CallWithPointerArgumentCount, 0);
887   EnableDetailedFunctionProperties.setValue(false);
888 }
889 
890 TEST_F(FunctionPropertiesAnalysisTest, IntrinsicCount) {
891   LLVMContext C;
892   std::unique_ptr<Module> M = makeLLVMModule(C,
893                                              R"IR(
894 define float @f1(float %a) {
895   %b = call float @llvm.cos.f32(float %a)
896   ret float %b
897 }
898 declare float @llvm.cos.f32(float)
899 )IR");
900 
901   Function *F1 = M->getFunction("f1");
902   EnableDetailedFunctionProperties.setValue(true);
903   FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);
904   EXPECT_EQ(DetailedF1Properties.IntrinsicCount, 1);
905   EXPECT_EQ(DetailedF1Properties.DirectCallCount, 1);
906   EXPECT_EQ(DetailedF1Properties.IndirectCallCount, 0);
907   EXPECT_EQ(DetailedF1Properties.CallReturnsIntegerCount, 0);
908   EXPECT_EQ(DetailedF1Properties.CallReturnsFloatCount, 1);
909   EXPECT_EQ(DetailedF1Properties.CallReturnsPointerCount, 0);
910   EXPECT_EQ(DetailedF1Properties.CallWithManyArgumentsCount, 0);
911   EXPECT_EQ(DetailedF1Properties.CallWithPointerArgumentCount, 0);
912   EnableDetailedFunctionProperties.setValue(false);
913 }
914 
915 TEST_F(FunctionPropertiesAnalysisTest, FunctionCallMetrics) {
916   LLVMContext C;
917   std::unique_ptr<Module> M = makeLLVMModule(C,
918                                              R"IR(
919 define i64 @f1(i64 %a) {
920   %b = call i64 @f2(i64 %a, i64 %a, i64 %a, i64 %a, i64 %a)
921   %c = call ptr @f3()
922   call void @f4(ptr %c)
923   %d = call float @f5()
924   %e = call i64 %c(i64 %b)
925   ret i64 %b
926 }
927 
928 declare i64 @f2(i64,i64,i64,i64,i64)
929 declare ptr @f3()
930 declare void @f4(ptr)
931 declare float @f5()
932 )IR");
933 
934   Function *F1 = M->getFunction("f1");
935   EnableDetailedFunctionProperties.setValue(true);
936   FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);
937   EXPECT_EQ(DetailedF1Properties.IntrinsicCount, 0);
938   EXPECT_EQ(DetailedF1Properties.DirectCallCount, 4);
939   EXPECT_EQ(DetailedF1Properties.IndirectCallCount, 1);
940   EXPECT_EQ(DetailedF1Properties.CallReturnsIntegerCount, 2);
941   EXPECT_EQ(DetailedF1Properties.CallReturnsFloatCount, 1);
942   EXPECT_EQ(DetailedF1Properties.CallReturnsPointerCount, 1);
943   EXPECT_EQ(DetailedF1Properties.CallWithManyArgumentsCount, 1);
944   EXPECT_EQ(DetailedF1Properties.CallWithPointerArgumentCount, 1);
945   EnableDetailedFunctionProperties.setValue(false);
946 }
947 
948 TEST_F(FunctionPropertiesAnalysisTest, CriticalEdge) {
949   LLVMContext C;
950   std::unique_ptr<Module> M = makeLLVMModule(C,
951                                              R"IR(
952 define i64 @f1(i64 %a) {
953   %b = icmp eq i64 %a, 1
954   br i1 %b, label %TopBlock1, label %TopBlock2
955 TopBlock1:
956   %c = add i64 %a, 1
957   %e = icmp eq i64 %c, 2
958   br i1 %e, label %BottomBlock1, label %BottomBlock2
959 TopBlock2:
960   %d = add i64 %a, 2
961   br label %BottomBlock2
962 BottomBlock1:
963   ret i64 0
964 BottomBlock2:
965   %f = phi i64 [ %c, %TopBlock1 ], [ %d, %TopBlock2 ]
966   ret i64 %f
967 }
968 )IR");
969 
970   Function *F1 = M->getFunction("f1");
971   EnableDetailedFunctionProperties.setValue(true);
972   FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);
973   EXPECT_EQ(DetailedF1Properties.CriticalEdgeCount, 1);
974   EnableDetailedFunctionProperties.setValue(false);
975 }
976 
977 
978 TEST_F(FunctionPropertiesAnalysisTest, FunctionReturnVectors) {
979   LLVMContext C;
980   std::unique_ptr<Module> M = makeLLVMModule(C,
981                                              R"IR(
982 define <4 x i64> @f1(<4 x i64> %a) {
983   %b = call <4 x i64> @f2()
984   %c = call <4 x float> @f3()
985   %d = call <4 x ptr> @f4()
986   ret <4 x i64> %b
987 }
988 
989 declare <4 x i64> @f2()
990 declare <4 x float> @f3()
991 declare <4 x ptr> @f4()
992 )IR");
993 
994   Function *F1 = M->getFunction("f1");
995   EnableDetailedFunctionProperties.setValue(true);
996   FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);
997   EXPECT_EQ(DetailedF1Properties.CallReturnsVectorIntCount, 1);
998   EXPECT_EQ(DetailedF1Properties.CallReturnsVectorFloatCount, 1);
999   EXPECT_EQ(DetailedF1Properties.CallReturnsVectorPointerCount, 1);
1000   EnableDetailedFunctionProperties.setValue(false);
1001 }
1002 
1003 TEST_F(FunctionPropertiesAnalysisTest, ReAddEdges) {
1004   LLVMContext C;
1005   std::unique_ptr<Module> M = makeLLVMModule(C, R"IR(
1006 define hidden void @f1(ptr noundef %destatep, i32 noundef %offset, i8 noundef zeroext %byte1) {
1007 entry:
1008   %cmp = icmp eq i8 %byte1, 0
1009   br i1 %cmp, label %if.then, label %if.else
1010 
1011 if.then:                                          ; preds = %entry
1012   call fastcc void @f2(ptr noundef %destatep, i32 noundef 37, i32 noundef 600)
1013   %and = and i32 %offset, 3
1014   switch i32 %and, label %default.unreachable [
1015     i32 0, label %sw.bb
1016     i32 1, label %sw.bb1
1017     i32 2, label %sw.bb1
1018     i32 3, label %if.end
1019   ]
1020 
1021 sw.bb:                                            ; preds = %if.then
1022   call fastcc void @f2(ptr noundef %destatep, i32 noundef 57, i32 noundef 600)
1023   br label %if.end
1024 
1025 sw.bb1:                                           ; preds = %if.then, %if.then
1026   call fastcc void @f2(ptr noundef %destatep, i32 noundef 56, i32 noundef 600) #34
1027   br label %if.end
1028 
1029 default.unreachable:                              ; preds = %if.then
1030   unreachable
1031 
1032 if.else:                                          ; preds = %entry
1033   call fastcc void @f2(ptr noundef %destatep, i32 noundef 56, i32 noundef 600)
1034   br label %if.end
1035 
1036 if.end:                                           ; preds = %sw.bb, %sw.bb1, %if.then, %if.else
1037   ret void
1038 }
1039 
1040 define internal fastcc void @f2(ptr nocapture noundef %destatep, i32 noundef %r_enc, i32 noundef %whack) {
1041 entry:
1042   %enc_prob = getelementptr inbounds nuw i8, ptr %destatep, i32 512
1043   %arrayidx = getelementptr inbounds [67 x i32], ptr %enc_prob, i32 0, i32 %r_enc
1044   %0 = load i32, ptr %arrayidx, align 4
1045   %sub = sub nsw i32 %0, %whack
1046   store i32 %sub, ptr %arrayidx, align 4
1047   ret void
1048 }
1049   )IR");
1050   auto *F1 = M->getFunction("f1");
1051   auto *F2 = M->getFunction("f2");
1052   auto *CB = [&]() -> CallBase * {
1053     for (auto &BB : *F1)
1054       for (auto &I : BB)
1055         if (auto *CB = dyn_cast<CallBase>(&I);
1056             CB && CB->getCalledFunction() && CB->getCalledFunction() == F2)
1057           return CB;
1058     return nullptr;
1059   }();
1060   ASSERT_NE(CB, nullptr);
1061   auto FPI = buildFPI(*F1);
1062   FunctionPropertiesUpdater FPU(FPI, *CB);
1063   InlineFunctionInfo IFI;
1064   auto IR = llvm::InlineFunction(*CB, IFI);
1065   EXPECT_TRUE(IR.isSuccess());
1066   invalidate(*F1);
1067   EXPECT_TRUE(FPU.finishAndTest(FAM));
1068 }
1069 
1070 TEST_F(FunctionPropertiesAnalysisTest, InvokeLandingCanStillBeReached) {
1071   LLVMContext C;
1072   // %lpad is reachable from a block not involved in the inlining decision. We
1073   // make sure that's not the entry - otherwise the DT will be recomputed from
1074   // scratch. The idea here is that the edge known to the inliner to potentially
1075   // disappear - %lpad->%ehcleanup -should survive because it is still reachable
1076   // from %middle.
1077   std::unique_ptr<Module> M = makeLLVMModule(C,
1078                                              R"IR(
1079 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
1080 target triple = "x86_64-pc-linux-gnu"
1081 
1082 define i64 @f1(i32 noundef %value) {
1083 entry:
1084   br label %middle
1085 middle:
1086   %c = icmp eq i32 %value, 0
1087   br i1 %c, label %invoke, label %lpad
1088 invoke:
1089   invoke fastcc void @f2() to label %cont unwind label %lpad
1090 cont:
1091   br label %exit
1092 lpad:
1093   %lp = landingpad i32 cleanup
1094   br label %ehcleanup
1095 ehcleanup:
1096   resume i32 0
1097 exit:
1098   ret i64 1
1099 }
1100 define void @f2() {
1101   ret void
1102 }
1103 )IR");
1104 
1105   Function *F1 = M->getFunction("f1");
1106   CallBase *CB = findCall(*F1);
1107   EXPECT_NE(CB, nullptr);
1108 
1109   auto FPI = buildFPI(*F1);
1110   FunctionPropertiesUpdater FPU(FPI, *CB);
1111   InlineFunctionInfo IFI;
1112   auto IR = llvm::InlineFunction(*CB, IFI);
1113   EXPECT_TRUE(IR.isSuccess());
1114   invalidate(*F1);
1115   EXPECT_TRUE(FPU.finishAndTest(FAM));
1116 }
1117 } // end anonymous namespace
1118