xref: /llvm-project/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp (revision 1991aa6b48845f31ff4e69a960b04086ff68ce3e)
12f56046dSTarindu Jayatilaka //===- FunctionPropertiesAnalysisTest.cpp - Function Properties Unit Tests-===//
2418121c3STarindu Jayatilaka //
3418121c3STarindu Jayatilaka // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4418121c3STarindu Jayatilaka // See https://llvm.org/LICENSE.txt for license information.
5418121c3STarindu Jayatilaka // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6418121c3STarindu Jayatilaka //
7418121c3STarindu Jayatilaka //===----------------------------------------------------------------------===//
8418121c3STarindu Jayatilaka 
9418121c3STarindu Jayatilaka #include "llvm/Analysis/FunctionPropertiesAnalysis.h"
10f46dd19bSMircea Trofin #include "llvm/Analysis/AliasAnalysis.h"
1171c3a551Sserge-sans-paille #include "llvm/Analysis/LoopInfo.h"
12418121c3STarindu Jayatilaka #include "llvm/AsmParser/Parser.h"
1306283661STarindu Jayatilaka #include "llvm/IR/Dominators.h"
14418121c3STarindu Jayatilaka #include "llvm/IR/Instructions.h"
15418121c3STarindu Jayatilaka #include "llvm/IR/LLVMContext.h"
16418121c3STarindu Jayatilaka #include "llvm/IR/Module.h"
17f46dd19bSMircea Trofin #include "llvm/IR/PassManager.h"
18f46dd19bSMircea Trofin #include "llvm/Passes/PassBuilder.h"
1922a1f998SMircea Trofin #include "llvm/Passes/StandardInstrumentations.h"
20418121c3STarindu Jayatilaka #include "llvm/Support/SourceMgr.h"
21f46dd19bSMircea Trofin #include "llvm/Transforms/Utils/Cloning.h"
22418121c3STarindu Jayatilaka #include "gtest/gtest.h"
23f46dd19bSMircea Trofin #include <cstring>
24418121c3STarindu Jayatilaka 
25418121c3STarindu Jayatilaka using namespace llvm;
26fe6bb84cSAiden Grossman 
272d854dd3SFangrui Song namespace llvm {
28fe6bb84cSAiden Grossman extern cl::opt<bool> EnableDetailedFunctionProperties;
29fe6bb84cSAiden Grossman extern cl::opt<bool> BigBasicBlockInstructionThreshold;
30fe6bb84cSAiden Grossman extern cl::opt<bool> MediumBasicBlockInstrutionThreshold;
312d854dd3SFangrui Song } // namespace llvm
32fe6bb84cSAiden Grossman 
3306283661STarindu Jayatilaka namespace {
34418121c3STarindu Jayatilaka 
3506283661STarindu Jayatilaka class FunctionPropertiesAnalysisTest : public testing::Test {
3622a1f998SMircea Trofin public:
3722a1f998SMircea Trofin   FunctionPropertiesAnalysisTest() {
3822a1f998SMircea Trofin     FAM.registerPass([&] { return DominatorTreeAnalysis(); });
3922a1f998SMircea Trofin     FAM.registerPass([&] { return LoopAnalysis(); });
4022a1f998SMircea Trofin     FAM.registerPass([&] { return PassInstrumentationAnalysis(); });
4122a1f998SMircea Trofin   }
4222a1f998SMircea Trofin 
4306283661STarindu Jayatilaka protected:
4406283661STarindu Jayatilaka   std::unique_ptr<DominatorTree> DT;
4506283661STarindu Jayatilaka   std::unique_ptr<LoopInfo> LI;
4622a1f998SMircea Trofin   FunctionAnalysisManager FAM;
4706283661STarindu Jayatilaka 
4806283661STarindu Jayatilaka   FunctionPropertiesInfo buildFPI(Function &F) {
4922a1f998SMircea Trofin     return FunctionPropertiesInfo::getFunctionPropertiesInfo(F, FAM);
5022a1f998SMircea Trofin   }
5122a1f998SMircea Trofin 
5222a1f998SMircea Trofin   void invalidate(Function &F) {
5322a1f998SMircea Trofin     PreservedAnalyses PA = PreservedAnalyses::none();
5422a1f998SMircea Trofin     FAM.invalidate(F, PA);
5506283661STarindu Jayatilaka   }
5606283661STarindu Jayatilaka 
5706283661STarindu Jayatilaka   std::unique_ptr<Module> makeLLVMModule(LLVMContext &C, const char *IR) {
58418121c3STarindu Jayatilaka     SMDiagnostic Err;
59418121c3STarindu Jayatilaka     std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
60418121c3STarindu Jayatilaka     if (!Mod)
61418121c3STarindu Jayatilaka       Err.print("MLAnalysisTests", errs());
62418121c3STarindu Jayatilaka     return Mod;
63418121c3STarindu Jayatilaka   }
64f46dd19bSMircea Trofin 
65f46dd19bSMircea Trofin   CallBase* findCall(Function& F, const char* Name = nullptr) {
66f46dd19bSMircea Trofin     for (auto &BB : F)
67f46dd19bSMircea Trofin       for (auto &I : BB )
68f46dd19bSMircea Trofin         if (auto *CB = dyn_cast<CallBase>(&I))
69f46dd19bSMircea Trofin           if (!Name || CB->getName() == Name)
70f46dd19bSMircea Trofin             return CB;
71f46dd19bSMircea Trofin     return nullptr;
72f46dd19bSMircea Trofin   }
7306283661STarindu Jayatilaka };
74418121c3STarindu Jayatilaka 
7506283661STarindu Jayatilaka TEST_F(FunctionPropertiesAnalysisTest, BasicTest) {
76418121c3STarindu Jayatilaka   LLVMContext C;
7706283661STarindu Jayatilaka   std::unique_ptr<Module> M = makeLLVMModule(C,
78418121c3STarindu Jayatilaka                                              R"IR(
79418121c3STarindu Jayatilaka target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
80418121c3STarindu Jayatilaka target triple = "x86_64-pc-linux-gnu"
81418121c3STarindu Jayatilaka declare i32 @f1(i32)
82418121c3STarindu Jayatilaka declare i32 @f2(i32)
83418121c3STarindu Jayatilaka define i32 @branches(i32) {
84418121c3STarindu Jayatilaka   %cond = icmp slt i32 %0, 3
85418121c3STarindu Jayatilaka   br i1 %cond, label %then, label %else
86418121c3STarindu Jayatilaka then:
87418121c3STarindu Jayatilaka   %ret.1 = call i32 @f1(i32 %0)
88418121c3STarindu Jayatilaka   br label %last.block
89418121c3STarindu Jayatilaka else:
90418121c3STarindu Jayatilaka   %ret.2 = call i32 @f2(i32 %0)
91418121c3STarindu Jayatilaka   br label %last.block
92418121c3STarindu Jayatilaka last.block:
93418121c3STarindu Jayatilaka   %ret = phi i32 [%ret.1, %then], [%ret.2, %else]
94418121c3STarindu Jayatilaka   ret i32 %ret
95418121c3STarindu Jayatilaka }
96418121c3STarindu Jayatilaka define internal i32 @top() {
97418121c3STarindu Jayatilaka   %1 = call i32 @branches(i32 2)
98418121c3STarindu Jayatilaka   %2 = call i32 @f1(i32 %1)
99418121c3STarindu Jayatilaka   ret i32 %2
100418121c3STarindu Jayatilaka }
101418121c3STarindu Jayatilaka )IR");
102418121c3STarindu Jayatilaka 
10306283661STarindu Jayatilaka   Function *BranchesFunction = M->getFunction("branches");
10406283661STarindu Jayatilaka   FunctionPropertiesInfo BranchesFeatures = buildFPI(*BranchesFunction);
105418121c3STarindu Jayatilaka   EXPECT_EQ(BranchesFeatures.BasicBlockCount, 4);
106418121c3STarindu Jayatilaka   EXPECT_EQ(BranchesFeatures.BlocksReachedFromConditionalInstruction, 2);
107418121c3STarindu Jayatilaka   // 2 Users: top is one. The other is added because @branches is not internal,
108418121c3STarindu Jayatilaka   // so it may have external callers.
109418121c3STarindu Jayatilaka   EXPECT_EQ(BranchesFeatures.Uses, 2);
11006283661STarindu Jayatilaka   EXPECT_EQ(BranchesFeatures.DirectCallsToDefinedFunctions, 0);
11106283661STarindu Jayatilaka   EXPECT_EQ(BranchesFeatures.LoadInstCount, 0);
11206283661STarindu Jayatilaka   EXPECT_EQ(BranchesFeatures.StoreInstCount, 0);
11306283661STarindu Jayatilaka   EXPECT_EQ(BranchesFeatures.MaxLoopDepth, 0);
11406283661STarindu Jayatilaka   EXPECT_EQ(BranchesFeatures.TopLevelLoopCount, 0);
115418121c3STarindu Jayatilaka 
11606283661STarindu Jayatilaka   Function *TopFunction = M->getFunction("top");
11706283661STarindu Jayatilaka   FunctionPropertiesInfo TopFeatures = buildFPI(*TopFunction);
118418121c3STarindu Jayatilaka   EXPECT_EQ(TopFeatures.BasicBlockCount, 1);
119418121c3STarindu Jayatilaka   EXPECT_EQ(TopFeatures.BlocksReachedFromConditionalInstruction, 0);
120418121c3STarindu Jayatilaka   EXPECT_EQ(TopFeatures.Uses, 0);
12106283661STarindu Jayatilaka   EXPECT_EQ(TopFeatures.DirectCallsToDefinedFunctions, 1);
12206283661STarindu Jayatilaka   EXPECT_EQ(BranchesFeatures.LoadInstCount, 0);
12306283661STarindu Jayatilaka   EXPECT_EQ(BranchesFeatures.StoreInstCount, 0);
12406283661STarindu Jayatilaka   EXPECT_EQ(BranchesFeatures.MaxLoopDepth, 0);
12506283661STarindu Jayatilaka   EXPECT_EQ(BranchesFeatures.TopLevelLoopCount, 0);
126fe6bb84cSAiden Grossman 
127fe6bb84cSAiden Grossman   EnableDetailedFunctionProperties.setValue(true);
128fe6bb84cSAiden Grossman   FunctionPropertiesInfo DetailedBranchesFeatures = buildFPI(*BranchesFunction);
129fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithSingleSuccessor, 2);
130fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithTwoSuccessors, 1);
131fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithMoreThanTwoSuccessors, 0);
132fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithSinglePredecessor, 2);
133fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithTwoPredecessors, 1);
134fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithMoreThanTwoPredecessors, 0);
135fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.BigBasicBlocks, 0);
136fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.MediumBasicBlocks, 0);
137fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.SmallBasicBlocks, 4);
138fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.CastInstructionCount, 0);
139fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.FloatingPointInstructionCount, 0);
140fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.IntegerInstructionCount, 4);
141b8f191e0SAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.ConstantIntOperandCount, 1);
142b8f191e0SAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.ConstantFPOperandCount, 0);
143b8f191e0SAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.ConstantOperandCount, 0);
144b8f191e0SAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.InstructionOperandCount, 4);
145b8f191e0SAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.BasicBlockOperandCount, 4);
146b8f191e0SAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.GlobalValueOperandCount, 2);
147b8f191e0SAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.InlineAsmOperandCount, 0);
148b8f191e0SAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.ArgumentOperandCount, 3);
149b8f191e0SAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.UnknownOperandCount, 0);
150aad3641eSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.CriticalEdgeCount, 0);
151aad3641eSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.ControlFlowEdgeCount, 4);
152aad3641eSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.UnconditionalBranchCount, 2);
153aad3641eSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.IntrinsicCount, 0);
154aad3641eSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.DirectCallCount, 2);
155aad3641eSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.IndirectCallCount, 0);
156aad3641eSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.CallReturnsIntegerCount, 2);
157aad3641eSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.CallReturnsFloatCount, 0);
158aad3641eSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.CallReturnsPointerCount, 0);
159aad3641eSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.CallWithManyArgumentsCount, 0);
160aad3641eSAiden Grossman   EXPECT_EQ(DetailedBranchesFeatures.CallWithPointerArgumentCount, 0);
161fe6bb84cSAiden Grossman   EnableDetailedFunctionProperties.setValue(false);
162fe6bb84cSAiden Grossman }
163fe6bb84cSAiden Grossman 
164fe6bb84cSAiden Grossman TEST_F(FunctionPropertiesAnalysisTest, DifferentPredecessorSuccessorCounts) {
165fe6bb84cSAiden Grossman   LLVMContext C;
166fe6bb84cSAiden Grossman   std::unique_ptr<Module> M = makeLLVMModule(C,
167fe6bb84cSAiden Grossman                                              R"IR(
168fe6bb84cSAiden Grossman define i64 @f1() {
169fe6bb84cSAiden Grossman   br i1 0, label %br1, label %finally
170fe6bb84cSAiden Grossman br1:
171fe6bb84cSAiden Grossman   ret i64 0
172fe6bb84cSAiden Grossman finally:
173fe6bb84cSAiden Grossman   ret i64 3
174fe6bb84cSAiden Grossman }
175fe6bb84cSAiden Grossman )IR");
176fe6bb84cSAiden Grossman 
177fe6bb84cSAiden Grossman   Function *F1 = M->getFunction("f1");
178fe6bb84cSAiden Grossman   EnableDetailedFunctionProperties.setValue(true);
179fe6bb84cSAiden Grossman   FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);
180fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithSingleSuccessor, 0);
181fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithTwoSuccessors, 1);
182fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithMoreThanTwoSuccessors, 0);
183fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithSinglePredecessor, 2);
184fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithTwoPredecessors, 0);
185fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithMoreThanTwoPredecessors, 0);
186fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedF1Properties.BigBasicBlocks, 0);
187fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedF1Properties.MediumBasicBlocks, 0);
188fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedF1Properties.SmallBasicBlocks, 3);
189fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CastInstructionCount, 0);
190fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedF1Properties.FloatingPointInstructionCount, 0);
191fe6bb84cSAiden Grossman   EXPECT_EQ(DetailedF1Properties.IntegerInstructionCount, 0);
192b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.ConstantIntOperandCount, 3);
193b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.ConstantFPOperandCount, 0);
194b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.ConstantOperandCount, 0);
195b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.InstructionOperandCount, 0);
196b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.BasicBlockOperandCount, 2);
197b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.GlobalValueOperandCount, 0);
198b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.InlineAsmOperandCount, 0);
199b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.ArgumentOperandCount, 0);
200b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.UnknownOperandCount, 0);
201aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CriticalEdgeCount, 0);
202aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.ControlFlowEdgeCount, 2);
203aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.UnconditionalBranchCount, 0);
204aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.IntrinsicCount, 0);
205aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.DirectCallCount, 0);
206aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.IndirectCallCount, 0);
207aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallReturnsIntegerCount, 0);
208aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallReturnsFloatCount, 0);
209aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallReturnsPointerCount, 0);
210aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallWithManyArgumentsCount, 0);
211aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallWithPointerArgumentCount, 0);
212fe6bb84cSAiden Grossman   EnableDetailedFunctionProperties.setValue(false);
213418121c3STarindu Jayatilaka }
214f46dd19bSMircea Trofin 
215f46dd19bSMircea Trofin TEST_F(FunctionPropertiesAnalysisTest, InlineSameBBSimple) {
216f46dd19bSMircea Trofin   LLVMContext C;
217f46dd19bSMircea Trofin   std::unique_ptr<Module> M = makeLLVMModule(C,
218f46dd19bSMircea Trofin                                              R"IR(
219f46dd19bSMircea Trofin target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
220f46dd19bSMircea Trofin target triple = "x86_64-pc-linux-gnu"
221f46dd19bSMircea Trofin define i32 @f1(i32 %a) {
222f46dd19bSMircea Trofin   %b = call i32 @f2(i32 %a)
223f46dd19bSMircea Trofin   %c = add i32 %b, 2
224f46dd19bSMircea Trofin   ret i32 %c
225f46dd19bSMircea Trofin }
226f46dd19bSMircea Trofin 
227f46dd19bSMircea Trofin define i32 @f2(i32 %a) {
228f46dd19bSMircea Trofin   %b = add i32 %a, 1
229f46dd19bSMircea Trofin   ret i32 %b
230f46dd19bSMircea Trofin }
231f46dd19bSMircea Trofin )IR");
232f46dd19bSMircea Trofin 
233f46dd19bSMircea Trofin   Function *F1 = M->getFunction("f1");
234f46dd19bSMircea Trofin   CallBase* CB = findCall(*F1, "b");
235f46dd19bSMircea Trofin   EXPECT_NE(CB, nullptr);
236f46dd19bSMircea Trofin 
237f46dd19bSMircea Trofin   FunctionPropertiesInfo ExpectedInitial;
238f46dd19bSMircea Trofin   ExpectedInitial.BasicBlockCount = 1;
239f46dd19bSMircea Trofin   ExpectedInitial.TotalInstructionCount = 3;
240f46dd19bSMircea Trofin   ExpectedInitial.Uses = 1;
241f46dd19bSMircea Trofin   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
242f46dd19bSMircea Trofin 
243f46dd19bSMircea Trofin   FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;
244f46dd19bSMircea Trofin   ExpectedFinal.DirectCallsToDefinedFunctions = 0;
245f46dd19bSMircea Trofin 
246f46dd19bSMircea Trofin   auto FPI = buildFPI(*F1);
247f46dd19bSMircea Trofin   EXPECT_EQ(FPI, ExpectedInitial);
248f46dd19bSMircea Trofin 
249f46dd19bSMircea Trofin   FunctionPropertiesUpdater FPU(FPI, *CB);
250f46dd19bSMircea Trofin   InlineFunctionInfo IFI;
251f46dd19bSMircea Trofin   auto IR = llvm::InlineFunction(*CB, IFI);
252f46dd19bSMircea Trofin   EXPECT_TRUE(IR.isSuccess());
25322a1f998SMircea Trofin   invalidate(*F1);
25401c5ec3dSMircea Trofin   EXPECT_TRUE(FPU.finishAndTest(FAM));
255f46dd19bSMircea Trofin   EXPECT_EQ(FPI, ExpectedFinal);
256f46dd19bSMircea Trofin }
257f46dd19bSMircea Trofin 
258f46dd19bSMircea Trofin TEST_F(FunctionPropertiesAnalysisTest, InlineSameBBLargerCFG) {
259f46dd19bSMircea Trofin   LLVMContext C;
260f46dd19bSMircea Trofin   std::unique_ptr<Module> M = makeLLVMModule(C,
261f46dd19bSMircea Trofin                                              R"IR(
262f46dd19bSMircea Trofin target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
263f46dd19bSMircea Trofin target triple = "x86_64-pc-linux-gnu"
264f46dd19bSMircea Trofin define i32 @f1(i32 %a) {
265f46dd19bSMircea Trofin entry:
266f46dd19bSMircea Trofin   %i = icmp slt i32 %a, 0
267f46dd19bSMircea Trofin   br i1 %i, label %if.then, label %if.else
268f46dd19bSMircea Trofin if.then:
269f46dd19bSMircea Trofin   %b = call i32 @f2(i32 %a)
270f46dd19bSMircea Trofin   %c1 = add i32 %b, 2
271f46dd19bSMircea Trofin   br label %end
272f46dd19bSMircea Trofin if.else:
273f46dd19bSMircea Trofin   %c2 = add i32 %a, 1
274f46dd19bSMircea Trofin   br label %end
275f46dd19bSMircea Trofin end:
276f46dd19bSMircea Trofin   %ret = phi i32 [%c1, %if.then],[%c2, %if.else]
277f46dd19bSMircea Trofin   ret i32 %ret
278f46dd19bSMircea Trofin }
279f46dd19bSMircea Trofin 
280f46dd19bSMircea Trofin define i32 @f2(i32 %a) {
281f46dd19bSMircea Trofin   %b = add i32 %a, 1
282f46dd19bSMircea Trofin   ret i32 %b
283f46dd19bSMircea Trofin }
284f46dd19bSMircea Trofin )IR");
285f46dd19bSMircea Trofin 
286f46dd19bSMircea Trofin   Function *F1 = M->getFunction("f1");
287f46dd19bSMircea Trofin   CallBase* CB = findCall(*F1, "b");
288f46dd19bSMircea Trofin   EXPECT_NE(CB, nullptr);
289f46dd19bSMircea Trofin 
290f46dd19bSMircea Trofin   FunctionPropertiesInfo ExpectedInitial;
291f46dd19bSMircea Trofin   ExpectedInitial.BasicBlockCount = 4;
292f46dd19bSMircea Trofin   ExpectedInitial.BlocksReachedFromConditionalInstruction = 2;
293f46dd19bSMircea Trofin   ExpectedInitial.TotalInstructionCount = 9;
294f46dd19bSMircea Trofin   ExpectedInitial.Uses = 1;
295f46dd19bSMircea Trofin   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
296f46dd19bSMircea Trofin 
297f46dd19bSMircea Trofin   FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;
298f46dd19bSMircea Trofin   ExpectedFinal.DirectCallsToDefinedFunctions = 0;
299f46dd19bSMircea Trofin 
300f46dd19bSMircea Trofin   auto FPI = buildFPI(*F1);
301f46dd19bSMircea Trofin   EXPECT_EQ(FPI, ExpectedInitial);
302f46dd19bSMircea Trofin 
303f46dd19bSMircea Trofin   FunctionPropertiesUpdater FPU(FPI, *CB);
304f46dd19bSMircea Trofin   InlineFunctionInfo IFI;
305f46dd19bSMircea Trofin   auto IR = llvm::InlineFunction(*CB, IFI);
306f46dd19bSMircea Trofin   EXPECT_TRUE(IR.isSuccess());
30722a1f998SMircea Trofin   invalidate(*F1);
30801c5ec3dSMircea Trofin   EXPECT_TRUE(FPU.finishAndTest(FAM));
309f46dd19bSMircea Trofin   EXPECT_EQ(FPI, ExpectedFinal);
310f46dd19bSMircea Trofin }
311f46dd19bSMircea Trofin 
312f46dd19bSMircea Trofin TEST_F(FunctionPropertiesAnalysisTest, InlineSameBBLoops) {
313f46dd19bSMircea Trofin   LLVMContext C;
314f46dd19bSMircea Trofin   std::unique_ptr<Module> M = makeLLVMModule(C,
315f46dd19bSMircea Trofin                                              R"IR(
316f46dd19bSMircea Trofin target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
317f46dd19bSMircea Trofin target triple = "x86_64-pc-linux-gnu"
318f46dd19bSMircea Trofin define i32 @f1(i32 %a) {
319f46dd19bSMircea Trofin entry:
320f46dd19bSMircea Trofin   %i = icmp slt i32 %a, 0
321f46dd19bSMircea Trofin   br i1 %i, label %if.then, label %if.else
322f46dd19bSMircea Trofin if.then:
323f46dd19bSMircea Trofin   %b = call i32 @f2(i32 %a)
324f46dd19bSMircea Trofin   %c1 = add i32 %b, 2
325f46dd19bSMircea Trofin   br label %end
326f46dd19bSMircea Trofin if.else:
327f46dd19bSMircea Trofin   %c2 = add i32 %a, 1
328f46dd19bSMircea Trofin   br label %end
329f46dd19bSMircea Trofin end:
330f46dd19bSMircea Trofin   %ret = phi i32 [%c1, %if.then],[%c2, %if.else]
331f46dd19bSMircea Trofin   ret i32 %ret
332f46dd19bSMircea Trofin }
333f46dd19bSMircea Trofin 
334f46dd19bSMircea Trofin define i32 @f2(i32 %a) {
335f46dd19bSMircea Trofin entry:
336f46dd19bSMircea Trofin   br label %loop
337f46dd19bSMircea Trofin loop:
338f46dd19bSMircea Trofin   %indvar = phi i32 [%indvar.next, %loop], [0, %entry]
339f46dd19bSMircea Trofin   %b = add i32 %a, %indvar
340f46dd19bSMircea Trofin   %indvar.next = add i32 %indvar, 1
341f46dd19bSMircea Trofin   %cond = icmp slt i32 %indvar.next, %a
342f46dd19bSMircea Trofin   br i1 %cond, label %loop, label %exit
343f46dd19bSMircea Trofin exit:
344f46dd19bSMircea Trofin   ret i32 %b
345f46dd19bSMircea Trofin }
346f46dd19bSMircea Trofin )IR");
347f46dd19bSMircea Trofin 
348f46dd19bSMircea Trofin   Function *F1 = M->getFunction("f1");
349f46dd19bSMircea Trofin   CallBase* CB = findCall(*F1, "b");
350f46dd19bSMircea Trofin   EXPECT_NE(CB, nullptr);
351f46dd19bSMircea Trofin 
352f46dd19bSMircea Trofin   FunctionPropertiesInfo ExpectedInitial;
353f46dd19bSMircea Trofin   ExpectedInitial.BasicBlockCount = 4;
354f46dd19bSMircea Trofin   ExpectedInitial.BlocksReachedFromConditionalInstruction = 2;
355f46dd19bSMircea Trofin   ExpectedInitial.TotalInstructionCount = 9;
356f46dd19bSMircea Trofin   ExpectedInitial.Uses = 1;
357f46dd19bSMircea Trofin   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
358f46dd19bSMircea Trofin 
359f46dd19bSMircea Trofin   FunctionPropertiesInfo ExpectedFinal;
360f46dd19bSMircea Trofin   ExpectedFinal.BasicBlockCount = 6;
361f46dd19bSMircea Trofin   ExpectedFinal.BlocksReachedFromConditionalInstruction = 4;
362f46dd19bSMircea Trofin   ExpectedFinal.Uses = 1;
363f46dd19bSMircea Trofin   ExpectedFinal.MaxLoopDepth = 1;
364f46dd19bSMircea Trofin   ExpectedFinal.TopLevelLoopCount = 1;
365f46dd19bSMircea Trofin   ExpectedFinal.TotalInstructionCount = 14;
366f46dd19bSMircea Trofin 
367f46dd19bSMircea Trofin   auto FPI = buildFPI(*F1);
368f46dd19bSMircea Trofin   EXPECT_EQ(FPI, ExpectedInitial);
369f46dd19bSMircea Trofin   FunctionPropertiesUpdater FPU(FPI, *CB);
370f46dd19bSMircea Trofin   InlineFunctionInfo IFI;
371f46dd19bSMircea Trofin 
372f46dd19bSMircea Trofin   auto IR = llvm::InlineFunction(*CB, IFI);
373f46dd19bSMircea Trofin   EXPECT_TRUE(IR.isSuccess());
37422a1f998SMircea Trofin   invalidate(*F1);
37501c5ec3dSMircea Trofin   EXPECT_TRUE(FPU.finishAndTest(FAM));
376f46dd19bSMircea Trofin   EXPECT_EQ(FPI, ExpectedFinal);
377f46dd19bSMircea Trofin }
378f46dd19bSMircea Trofin 
379f46dd19bSMircea Trofin TEST_F(FunctionPropertiesAnalysisTest, InvokeSimple) {
380f46dd19bSMircea Trofin   LLVMContext C;
381f46dd19bSMircea Trofin   std::unique_ptr<Module> M = makeLLVMModule(C,
382f46dd19bSMircea Trofin                                              R"IR(
383f46dd19bSMircea Trofin target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
384f46dd19bSMircea Trofin target triple = "x86_64-pc-linux-gnu"
385f46dd19bSMircea Trofin declare void @might_throw()
386f46dd19bSMircea Trofin 
387f46dd19bSMircea Trofin define internal void @callee() {
388f46dd19bSMircea Trofin entry:
389f46dd19bSMircea Trofin   call void @might_throw()
390f46dd19bSMircea Trofin   ret void
391f46dd19bSMircea Trofin }
392f46dd19bSMircea Trofin 
393f46dd19bSMircea Trofin define i32 @caller() personality i32 (...)* @__gxx_personality_v0 {
394f46dd19bSMircea Trofin entry:
395f46dd19bSMircea Trofin   invoke void @callee()
396f46dd19bSMircea Trofin       to label %cont unwind label %exc
397f46dd19bSMircea Trofin 
398f46dd19bSMircea Trofin cont:
399f46dd19bSMircea Trofin   ret i32 0
400f46dd19bSMircea Trofin 
401f46dd19bSMircea Trofin exc:
402f46dd19bSMircea Trofin   %exn = landingpad {i8*, i32}
403f46dd19bSMircea Trofin          cleanup
404f46dd19bSMircea Trofin   ret i32 1
405f46dd19bSMircea Trofin }
406f46dd19bSMircea Trofin 
407f46dd19bSMircea Trofin declare i32 @__gxx_personality_v0(...)
408f46dd19bSMircea Trofin )IR");
409f46dd19bSMircea Trofin 
410f46dd19bSMircea Trofin   Function *F1 = M->getFunction("caller");
411f46dd19bSMircea Trofin   CallBase* CB = findCall(*F1);
412f46dd19bSMircea Trofin   EXPECT_NE(CB, nullptr);
413f46dd19bSMircea Trofin 
414f46dd19bSMircea Trofin   auto FPI = buildFPI(*F1);
415f46dd19bSMircea Trofin   FunctionPropertiesUpdater FPU(FPI, *CB);
416f46dd19bSMircea Trofin   InlineFunctionInfo IFI;
417f46dd19bSMircea Trofin   auto IR = llvm::InlineFunction(*CB, IFI);
418f46dd19bSMircea Trofin   EXPECT_TRUE(IR.isSuccess());
41922a1f998SMircea Trofin   invalidate(*F1);
42001c5ec3dSMircea Trofin   EXPECT_TRUE(FPU.finishAndTest(FAM));
421a19ae77dSVasileios Porpodas   EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size());
422f46dd19bSMircea Trofin   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
423f46dd19bSMircea Trofin             F1->getInstructionCount());
424f46dd19bSMircea Trofin }
425f46dd19bSMircea Trofin 
426f46dd19bSMircea Trofin TEST_F(FunctionPropertiesAnalysisTest, InvokeUnreachableHandler) {
427f46dd19bSMircea Trofin   LLVMContext C;
428f46dd19bSMircea Trofin   std::unique_ptr<Module> M = makeLLVMModule(C,
429f46dd19bSMircea Trofin                                              R"IR(
430f46dd19bSMircea Trofin declare void @might_throw()
431f46dd19bSMircea Trofin 
432f46dd19bSMircea Trofin define internal i32 @callee() personality i32 (...)* @__gxx_personality_v0 {
433f46dd19bSMircea Trofin entry:
434f46dd19bSMircea Trofin   invoke void @might_throw()
435f46dd19bSMircea Trofin       to label %cont unwind label %exc
436f46dd19bSMircea Trofin 
437f46dd19bSMircea Trofin cont:
438f46dd19bSMircea Trofin   ret i32 0
439f46dd19bSMircea Trofin 
440f46dd19bSMircea Trofin exc:
441f46dd19bSMircea Trofin   %exn = landingpad {i8*, i32}
442f46dd19bSMircea Trofin          cleanup
443f46dd19bSMircea Trofin   resume { i8*, i32 } %exn
444f46dd19bSMircea Trofin }
445f46dd19bSMircea Trofin 
446f46dd19bSMircea Trofin define i32 @caller() personality i32 (...)* @__gxx_personality_v0 {
447f46dd19bSMircea Trofin entry:
448f46dd19bSMircea Trofin   %X = invoke i32 @callee()
449f46dd19bSMircea Trofin            to label %cont unwind label %Handler
450f46dd19bSMircea Trofin 
451f46dd19bSMircea Trofin cont:
452f46dd19bSMircea Trofin   ret i32 %X
453f46dd19bSMircea Trofin 
454f46dd19bSMircea Trofin Handler:
455f46dd19bSMircea Trofin   %exn = landingpad {i8*, i32}
456f46dd19bSMircea Trofin          cleanup
457f46dd19bSMircea Trofin   ret i32 1
458f46dd19bSMircea Trofin }
459f46dd19bSMircea Trofin 
460f46dd19bSMircea Trofin declare i32 @__gxx_personality_v0(...)
461f46dd19bSMircea Trofin )IR");
462f46dd19bSMircea Trofin 
463f46dd19bSMircea Trofin   Function *F1 = M->getFunction("caller");
464f46dd19bSMircea Trofin   CallBase* CB = findCall(*F1);
465f46dd19bSMircea Trofin   EXPECT_NE(CB, nullptr);
466f46dd19bSMircea Trofin 
467f46dd19bSMircea Trofin   auto FPI = buildFPI(*F1);
468f46dd19bSMircea Trofin   FunctionPropertiesUpdater FPU(FPI, *CB);
469f46dd19bSMircea Trofin   InlineFunctionInfo IFI;
470f46dd19bSMircea Trofin   auto IR = llvm::InlineFunction(*CB, IFI);
471f46dd19bSMircea Trofin   EXPECT_TRUE(IR.isSuccess());
47222a1f998SMircea Trofin   invalidate(*F1);
47301c5ec3dSMircea Trofin   EXPECT_TRUE(FPU.finishAndTest(FAM));
474a19ae77dSVasileios Porpodas   EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size() - 1);
475f46dd19bSMircea Trofin   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
476f46dd19bSMircea Trofin             F1->getInstructionCount() - 2);
47722a1f998SMircea Trofin   EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));
478f46dd19bSMircea Trofin }
479f46dd19bSMircea Trofin 
480f46dd19bSMircea Trofin TEST_F(FunctionPropertiesAnalysisTest, Rethrow) {
481f46dd19bSMircea Trofin   LLVMContext C;
482f46dd19bSMircea Trofin   std::unique_ptr<Module> M = makeLLVMModule(C,
483f46dd19bSMircea Trofin                                              R"IR(
484f46dd19bSMircea Trofin declare void @might_throw()
485f46dd19bSMircea Trofin 
486f46dd19bSMircea Trofin define internal i32 @callee() personality i32 (...)* @__gxx_personality_v0 {
487f46dd19bSMircea Trofin entry:
488f46dd19bSMircea Trofin   invoke void @might_throw()
489f46dd19bSMircea Trofin       to label %cont unwind label %exc
490f46dd19bSMircea Trofin 
491f46dd19bSMircea Trofin cont:
492f46dd19bSMircea Trofin   ret i32 0
493f46dd19bSMircea Trofin 
494f46dd19bSMircea Trofin exc:
495f46dd19bSMircea Trofin   %exn = landingpad {i8*, i32}
496f46dd19bSMircea Trofin          cleanup
497f46dd19bSMircea Trofin   resume { i8*, i32 } %exn
498f46dd19bSMircea Trofin }
499f46dd19bSMircea Trofin 
500f46dd19bSMircea Trofin define i32 @caller() personality i32 (...)* @__gxx_personality_v0 {
501f46dd19bSMircea Trofin entry:
502f46dd19bSMircea Trofin   %X = invoke i32 @callee()
503f46dd19bSMircea Trofin            to label %cont unwind label %Handler
504f46dd19bSMircea Trofin 
505f46dd19bSMircea Trofin cont:
506f46dd19bSMircea Trofin   ret i32 %X
507f46dd19bSMircea Trofin 
508f46dd19bSMircea Trofin Handler:
509f46dd19bSMircea Trofin   %exn = landingpad {i8*, i32}
510f46dd19bSMircea Trofin          cleanup
511f46dd19bSMircea Trofin   ret i32 1
512f46dd19bSMircea Trofin }
513f46dd19bSMircea Trofin 
514f46dd19bSMircea Trofin declare i32 @__gxx_personality_v0(...)
515f46dd19bSMircea Trofin )IR");
516f46dd19bSMircea Trofin 
517f46dd19bSMircea Trofin   Function *F1 = M->getFunction("caller");
518f46dd19bSMircea Trofin   CallBase* CB = findCall(*F1);
519f46dd19bSMircea Trofin   EXPECT_NE(CB, nullptr);
520f46dd19bSMircea Trofin 
521f46dd19bSMircea Trofin   auto FPI = buildFPI(*F1);
522f46dd19bSMircea Trofin   FunctionPropertiesUpdater FPU(FPI, *CB);
523f46dd19bSMircea Trofin   InlineFunctionInfo IFI;
524f46dd19bSMircea Trofin   auto IR = llvm::InlineFunction(*CB, IFI);
525f46dd19bSMircea Trofin   EXPECT_TRUE(IR.isSuccess());
52622a1f998SMircea Trofin   invalidate(*F1);
52701c5ec3dSMircea Trofin   EXPECT_TRUE(FPU.finishAndTest(FAM));
528a19ae77dSVasileios Porpodas   EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size() - 1);
529f46dd19bSMircea Trofin   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
530f46dd19bSMircea Trofin             F1->getInstructionCount() - 2);
53122a1f998SMircea Trofin   EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));
532f46dd19bSMircea Trofin }
533f46dd19bSMircea Trofin 
534f46dd19bSMircea Trofin TEST_F(FunctionPropertiesAnalysisTest, LPadChanges) {
535f46dd19bSMircea Trofin   LLVMContext C;
536f46dd19bSMircea Trofin   std::unique_ptr<Module> M = makeLLVMModule(C,
537f46dd19bSMircea Trofin                                              R"IR(
538f46dd19bSMircea Trofin declare void @external_func()
539f46dd19bSMircea Trofin 
540f46dd19bSMircea Trofin @exception_type1 = external global i8
541f46dd19bSMircea Trofin @exception_type2 = external global i8
542f46dd19bSMircea Trofin 
543f46dd19bSMircea Trofin 
544f46dd19bSMircea Trofin define internal void @inner() personality i8* null {
545f46dd19bSMircea Trofin   invoke void @external_func()
546f46dd19bSMircea Trofin       to label %cont unwind label %lpad
547f46dd19bSMircea Trofin cont:
548f46dd19bSMircea Trofin   ret void
549f46dd19bSMircea Trofin lpad:
550f46dd19bSMircea Trofin   %lp = landingpad i32
551f46dd19bSMircea Trofin       catch i8* @exception_type1
552f46dd19bSMircea Trofin   resume i32 %lp
553f46dd19bSMircea Trofin }
554f46dd19bSMircea Trofin 
555f46dd19bSMircea Trofin define void @outer() personality i8* null {
556f46dd19bSMircea Trofin   invoke void @inner()
557f46dd19bSMircea Trofin       to label %cont unwind label %lpad
558f46dd19bSMircea Trofin cont:
559f46dd19bSMircea Trofin   ret void
560f46dd19bSMircea Trofin lpad:
561f46dd19bSMircea Trofin   %lp = landingpad i32
562f46dd19bSMircea Trofin       cleanup
563f46dd19bSMircea Trofin       catch i8* @exception_type2
564f46dd19bSMircea Trofin   resume i32 %lp
565f46dd19bSMircea Trofin }
566f46dd19bSMircea Trofin 
567f46dd19bSMircea Trofin )IR");
568f46dd19bSMircea Trofin 
569f46dd19bSMircea Trofin   Function *F1 = M->getFunction("outer");
570f46dd19bSMircea Trofin   CallBase* CB = findCall(*F1);
571f46dd19bSMircea Trofin   EXPECT_NE(CB, nullptr);
572f46dd19bSMircea Trofin 
573f46dd19bSMircea Trofin   auto FPI = buildFPI(*F1);
574f46dd19bSMircea Trofin   FunctionPropertiesUpdater FPU(FPI, *CB);
575f46dd19bSMircea Trofin   InlineFunctionInfo IFI;
576f46dd19bSMircea Trofin   auto IR = llvm::InlineFunction(*CB, IFI);
577f46dd19bSMircea Trofin   EXPECT_TRUE(IR.isSuccess());
57822a1f998SMircea Trofin   invalidate(*F1);
57901c5ec3dSMircea Trofin   EXPECT_TRUE(FPU.finishAndTest(FAM));
580a19ae77dSVasileios Porpodas   EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size() - 1);
581f46dd19bSMircea Trofin   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
582f46dd19bSMircea Trofin             F1->getInstructionCount() - 2);
58322a1f998SMircea Trofin   EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));
584f46dd19bSMircea Trofin }
585f46dd19bSMircea Trofin 
586f46dd19bSMircea Trofin TEST_F(FunctionPropertiesAnalysisTest, LPadChangesConditional) {
587f46dd19bSMircea Trofin   LLVMContext C;
588f46dd19bSMircea Trofin   std::unique_ptr<Module> M = makeLLVMModule(C,
589f46dd19bSMircea Trofin                                              R"IR(
590f46dd19bSMircea Trofin declare void @external_func()
591f46dd19bSMircea Trofin 
592f46dd19bSMircea Trofin @exception_type1 = external global i8
593f46dd19bSMircea Trofin @exception_type2 = external global i8
594f46dd19bSMircea Trofin 
595f46dd19bSMircea Trofin 
596f46dd19bSMircea Trofin define internal void @inner() personality i8* null {
597f46dd19bSMircea Trofin   invoke void @external_func()
598f46dd19bSMircea Trofin       to label %cont unwind label %lpad
599f46dd19bSMircea Trofin cont:
600f46dd19bSMircea Trofin   ret void
601f46dd19bSMircea Trofin lpad:
602f46dd19bSMircea Trofin   %lp = landingpad i32
603f46dd19bSMircea Trofin       catch i8* @exception_type1
604f46dd19bSMircea Trofin   resume i32 %lp
605f46dd19bSMircea Trofin }
606f46dd19bSMircea Trofin 
607f46dd19bSMircea Trofin define void @outer(i32 %a) personality i8* null {
608f46dd19bSMircea Trofin entry:
609f46dd19bSMircea Trofin   %i = icmp slt i32 %a, 0
610f46dd19bSMircea Trofin   br i1 %i, label %if.then, label %cont
611f46dd19bSMircea Trofin if.then:
612f46dd19bSMircea Trofin   invoke void @inner()
613f46dd19bSMircea Trofin       to label %cont unwind label %lpad
614f46dd19bSMircea Trofin cont:
615f46dd19bSMircea Trofin   ret void
616f46dd19bSMircea Trofin lpad:
617f46dd19bSMircea Trofin   %lp = landingpad i32
618f46dd19bSMircea Trofin       cleanup
619f46dd19bSMircea Trofin       catch i8* @exception_type2
620f46dd19bSMircea Trofin   resume i32 %lp
621f46dd19bSMircea Trofin }
622f46dd19bSMircea Trofin 
623f46dd19bSMircea Trofin )IR");
624f46dd19bSMircea Trofin 
625f46dd19bSMircea Trofin   Function *F1 = M->getFunction("outer");
626f46dd19bSMircea Trofin   CallBase* CB = findCall(*F1);
627f46dd19bSMircea Trofin   EXPECT_NE(CB, nullptr);
628f46dd19bSMircea Trofin 
629f46dd19bSMircea Trofin   auto FPI = buildFPI(*F1);
630f46dd19bSMircea Trofin   FunctionPropertiesUpdater FPU(FPI, *CB);
631f46dd19bSMircea Trofin   InlineFunctionInfo IFI;
632f46dd19bSMircea Trofin   auto IR = llvm::InlineFunction(*CB, IFI);
633f46dd19bSMircea Trofin   EXPECT_TRUE(IR.isSuccess());
63422a1f998SMircea Trofin   invalidate(*F1);
63501c5ec3dSMircea Trofin   EXPECT_TRUE(FPU.finishAndTest(FAM));
636a19ae77dSVasileios Porpodas   EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size() - 1);
637f46dd19bSMircea Trofin   EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),
638f46dd19bSMircea Trofin             F1->getInstructionCount() - 2);
63922a1f998SMircea Trofin   EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));
640f46dd19bSMircea Trofin }
641f46dd19bSMircea Trofin 
642b8c39eb2SMircea Trofin TEST_F(FunctionPropertiesAnalysisTest, InlineSameLoopBB) {
643b8c39eb2SMircea Trofin   LLVMContext C;
644b8c39eb2SMircea Trofin   std::unique_ptr<Module> M = makeLLVMModule(C,
645b8c39eb2SMircea Trofin                                              R"IR(
646b8c39eb2SMircea Trofin target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
647b8c39eb2SMircea Trofin target triple = "x86_64-pc-linux-gnu"
648b8c39eb2SMircea Trofin 
649b8c39eb2SMircea Trofin declare i32 @a()
650b8c39eb2SMircea Trofin declare i32 @b()
651b8c39eb2SMircea Trofin 
652b8c39eb2SMircea Trofin define i32 @f1(i32 %a) {
653b8c39eb2SMircea Trofin entry:
654b8c39eb2SMircea Trofin   br label %loop
655b8c39eb2SMircea Trofin loop:
656b8c39eb2SMircea Trofin   %i = call i32 @f2(i32 %a)
657b8c39eb2SMircea Trofin   %c = icmp slt i32 %i, %a
658b8c39eb2SMircea Trofin   br i1 %c, label %loop, label %end
659b8c39eb2SMircea Trofin end:
660b8c39eb2SMircea Trofin   %r = phi i32 [%i, %loop], [%a, %entry]
661b8c39eb2SMircea Trofin   ret i32 %r
662b8c39eb2SMircea Trofin }
663b8c39eb2SMircea Trofin 
664b8c39eb2SMircea Trofin define i32 @f2(i32 %a) {
665b8c39eb2SMircea Trofin   %cnd = icmp slt i32 %a, 0
666b8c39eb2SMircea Trofin   br i1 %cnd, label %then, label %else
667b8c39eb2SMircea Trofin then:
668b8c39eb2SMircea Trofin   %r1 = call i32 @a()
669b8c39eb2SMircea Trofin   br label %end
670b8c39eb2SMircea Trofin else:
671b8c39eb2SMircea Trofin   %r2 = call i32 @b()
672b8c39eb2SMircea Trofin   br label %end
673b8c39eb2SMircea Trofin end:
674b8c39eb2SMircea Trofin   %r = phi i32 [%r1, %then], [%r2, %else]
675b8c39eb2SMircea Trofin   ret i32 %r
676b8c39eb2SMircea Trofin }
677b8c39eb2SMircea Trofin )IR");
678b8c39eb2SMircea Trofin 
679b8c39eb2SMircea Trofin   Function *F1 = M->getFunction("f1");
680b8c39eb2SMircea Trofin   CallBase *CB = findCall(*F1);
681b8c39eb2SMircea Trofin   EXPECT_NE(CB, nullptr);
682b8c39eb2SMircea Trofin 
683b8c39eb2SMircea Trofin   FunctionPropertiesInfo ExpectedInitial;
684b8c39eb2SMircea Trofin   ExpectedInitial.BasicBlockCount = 3;
685b8c39eb2SMircea Trofin   ExpectedInitial.TotalInstructionCount = 6;
686b8c39eb2SMircea Trofin   ExpectedInitial.BlocksReachedFromConditionalInstruction = 2;
687b8c39eb2SMircea Trofin   ExpectedInitial.Uses = 1;
688b8c39eb2SMircea Trofin   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
689b8c39eb2SMircea Trofin   ExpectedInitial.MaxLoopDepth = 1;
690b8c39eb2SMircea Trofin   ExpectedInitial.TopLevelLoopCount = 1;
691b8c39eb2SMircea Trofin 
692b8c39eb2SMircea Trofin   FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;
693b8c39eb2SMircea Trofin   ExpectedFinal.BasicBlockCount = 6;
694b8c39eb2SMircea Trofin   ExpectedFinal.DirectCallsToDefinedFunctions = 0;
695b8c39eb2SMircea Trofin   ExpectedFinal.BlocksReachedFromConditionalInstruction = 4;
696b8c39eb2SMircea Trofin   ExpectedFinal.TotalInstructionCount = 12;
697b8c39eb2SMircea Trofin 
698b8c39eb2SMircea Trofin   auto FPI = buildFPI(*F1);
699b8c39eb2SMircea Trofin   EXPECT_EQ(FPI, ExpectedInitial);
700b8c39eb2SMircea Trofin 
701b8c39eb2SMircea Trofin   FunctionPropertiesUpdater FPU(FPI, *CB);
702b8c39eb2SMircea Trofin   InlineFunctionInfo IFI;
703b8c39eb2SMircea Trofin   auto IR = llvm::InlineFunction(*CB, IFI);
704b8c39eb2SMircea Trofin   EXPECT_TRUE(IR.isSuccess());
70522a1f998SMircea Trofin   invalidate(*F1);
70601c5ec3dSMircea Trofin   EXPECT_TRUE(FPU.finishAndTest(FAM));
70722a1f998SMircea Trofin   EXPECT_EQ(FPI, ExpectedFinal);
70822a1f998SMircea Trofin }
70922a1f998SMircea Trofin 
71022a1f998SMircea Trofin TEST_F(FunctionPropertiesAnalysisTest, Unreachable) {
71122a1f998SMircea Trofin   LLVMContext C;
71222a1f998SMircea Trofin   std::unique_ptr<Module> M = makeLLVMModule(C,
71322a1f998SMircea Trofin                                              R"IR(
71422a1f998SMircea Trofin target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
71522a1f998SMircea Trofin target triple = "x86_64-pc-linux-gnu"
71622a1f998SMircea Trofin 
71722a1f998SMircea Trofin define i64 @f1(i32 noundef %value) {
71822a1f998SMircea Trofin entry:
71922a1f998SMircea Trofin   br i1 true, label %cond.true, label %cond.false
72022a1f998SMircea Trofin 
72122a1f998SMircea Trofin cond.true:                                        ; preds = %entry
72222a1f998SMircea Trofin   %conv2 = sext i32 %value to i64
72322a1f998SMircea Trofin   br label %cond.end
72422a1f998SMircea Trofin 
72522a1f998SMircea Trofin cond.false:                                       ; preds = %entry
72622a1f998SMircea Trofin   %call3 = call noundef i64 @f2()
7273f8e4169SMircea Trofin   br label %extra
7283f8e4169SMircea Trofin 
7293f8e4169SMircea Trofin extra:
7303f8e4169SMircea Trofin   br label %extra2
7313f8e4169SMircea Trofin 
7323f8e4169SMircea Trofin extra2:
73322a1f998SMircea Trofin   br label %cond.end
73422a1f998SMircea Trofin 
73522a1f998SMircea Trofin cond.end:                                         ; preds = %cond.false, %cond.true
7363f8e4169SMircea Trofin   %cond = phi i64 [ %conv2, %cond.true ], [ %call3, %extra ]
73722a1f998SMircea Trofin   ret i64 %cond
73822a1f998SMircea Trofin }
73922a1f998SMircea Trofin 
74022a1f998SMircea Trofin define i64 @f2() {
74122a1f998SMircea Trofin entry:
74222a1f998SMircea Trofin   tail call void @llvm.trap()
74322a1f998SMircea Trofin   unreachable
74422a1f998SMircea Trofin }
74522a1f998SMircea Trofin 
74622a1f998SMircea Trofin declare void @llvm.trap()
74722a1f998SMircea Trofin )IR");
74822a1f998SMircea Trofin 
74922a1f998SMircea Trofin   Function *F1 = M->getFunction("f1");
75022a1f998SMircea Trofin   CallBase *CB = findCall(*F1);
75122a1f998SMircea Trofin   EXPECT_NE(CB, nullptr);
75222a1f998SMircea Trofin 
75322a1f998SMircea Trofin   FunctionPropertiesInfo ExpectedInitial;
7543f8e4169SMircea Trofin   ExpectedInitial.BasicBlockCount = 6;
7553f8e4169SMircea Trofin   ExpectedInitial.TotalInstructionCount = 9;
75622a1f998SMircea Trofin   ExpectedInitial.BlocksReachedFromConditionalInstruction = 2;
75722a1f998SMircea Trofin   ExpectedInitial.Uses = 1;
75822a1f998SMircea Trofin   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
75922a1f998SMircea Trofin 
76022a1f998SMircea Trofin   FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;
76122a1f998SMircea Trofin   ExpectedFinal.BasicBlockCount = 4;
76222a1f998SMircea Trofin   ExpectedFinal.DirectCallsToDefinedFunctions = 0;
76322a1f998SMircea Trofin   ExpectedFinal.TotalInstructionCount = 7;
76422a1f998SMircea Trofin 
76522a1f998SMircea Trofin   auto FPI = buildFPI(*F1);
76622a1f998SMircea Trofin   EXPECT_EQ(FPI, ExpectedInitial);
76722a1f998SMircea Trofin 
76822a1f998SMircea Trofin   FunctionPropertiesUpdater FPU(FPI, *CB);
76922a1f998SMircea Trofin   InlineFunctionInfo IFI;
77022a1f998SMircea Trofin   auto IR = llvm::InlineFunction(*CB, IFI);
77122a1f998SMircea Trofin   EXPECT_TRUE(IR.isSuccess());
77222a1f998SMircea Trofin   invalidate(*F1);
77301c5ec3dSMircea Trofin   EXPECT_TRUE(FPU.finishAndTest(FAM));
774b8c39eb2SMircea Trofin   EXPECT_EQ(FPI, ExpectedFinal);
775b8c39eb2SMircea Trofin }
776b8c39eb2SMircea Trofin 
7773f8e4169SMircea Trofin TEST_F(FunctionPropertiesAnalysisTest, InvokeSkipLP) {
7783f8e4169SMircea Trofin   LLVMContext C;
7793f8e4169SMircea Trofin   std::unique_ptr<Module> M = makeLLVMModule(C,
7803f8e4169SMircea Trofin                                              R"IR(
7813f8e4169SMircea Trofin target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
7823f8e4169SMircea Trofin target triple = "x86_64-pc-linux-gnu"
7833f8e4169SMircea Trofin 
7843f8e4169SMircea Trofin define i64 @f1(i32 noundef %value) {
7853f8e4169SMircea Trofin entry:
7863f8e4169SMircea Trofin   invoke fastcc void @f2() to label %cont unwind label %lpad
7873f8e4169SMircea Trofin cont:
7883f8e4169SMircea Trofin   ret i64 1
7893f8e4169SMircea Trofin lpad:
7903f8e4169SMircea Trofin   %lp = landingpad i32 cleanup
7913f8e4169SMircea Trofin   br label %ehcleanup
7923f8e4169SMircea Trofin ehcleanup:
7933f8e4169SMircea Trofin   resume i32 0
7943f8e4169SMircea Trofin }
7953f8e4169SMircea Trofin define void @f2() {
7963f8e4169SMircea Trofin   invoke noundef void @f3() to label %exit unwind label %lpad
7973f8e4169SMircea Trofin exit:
7983f8e4169SMircea Trofin   ret void
7993f8e4169SMircea Trofin lpad:
8003f8e4169SMircea Trofin   %lp = landingpad i32 cleanup
8013f8e4169SMircea Trofin   resume i32 %lp
8023f8e4169SMircea Trofin }
8033f8e4169SMircea Trofin declare void @f3()
8043f8e4169SMircea Trofin )IR");
8053f8e4169SMircea Trofin 
8063f8e4169SMircea Trofin   // The outcome of inlining will be that lpad becomes unreachable. The landing
8073f8e4169SMircea Trofin   // pad of the invoke inherited from f2 will land on a new bb which will branch
8083f8e4169SMircea Trofin   // to a bb containing the body of lpad.
8093f8e4169SMircea Trofin   Function *F1 = M->getFunction("f1");
8103f8e4169SMircea Trofin   CallBase *CB = findCall(*F1);
8113f8e4169SMircea Trofin   EXPECT_NE(CB, nullptr);
8123f8e4169SMircea Trofin 
8133f8e4169SMircea Trofin   FunctionPropertiesInfo ExpectedInitial;
8143f8e4169SMircea Trofin   ExpectedInitial.BasicBlockCount = 4;
8153f8e4169SMircea Trofin   ExpectedInitial.TotalInstructionCount = 5;
8163f8e4169SMircea Trofin   ExpectedInitial.BlocksReachedFromConditionalInstruction = 0;
8173f8e4169SMircea Trofin   ExpectedInitial.Uses = 1;
8183f8e4169SMircea Trofin   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
8193f8e4169SMircea Trofin 
8203f8e4169SMircea Trofin   FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;
8213f8e4169SMircea Trofin   ExpectedFinal.BasicBlockCount = 6;
8223f8e4169SMircea Trofin   ExpectedFinal.DirectCallsToDefinedFunctions = 0;
8233f8e4169SMircea Trofin   ExpectedFinal.TotalInstructionCount = 8;
8243f8e4169SMircea Trofin 
8253f8e4169SMircea Trofin   auto FPI = buildFPI(*F1);
8263f8e4169SMircea Trofin   EXPECT_EQ(FPI, ExpectedInitial);
8273f8e4169SMircea Trofin 
8283f8e4169SMircea Trofin   FunctionPropertiesUpdater FPU(FPI, *CB);
8293f8e4169SMircea Trofin   InlineFunctionInfo IFI;
8303f8e4169SMircea Trofin   auto IR = llvm::InlineFunction(*CB, IFI);
8313f8e4169SMircea Trofin   EXPECT_TRUE(IR.isSuccess());
8323f8e4169SMircea Trofin   invalidate(*F1);
83301c5ec3dSMircea Trofin   EXPECT_TRUE(FPU.finishAndTest(FAM));
8343f8e4169SMircea Trofin   EXPECT_EQ(FPI, ExpectedFinal);
8353f8e4169SMircea Trofin }
836b8f191e0SAiden Grossman 
837b8f191e0SAiden Grossman TEST_F(FunctionPropertiesAnalysisTest, DetailedOperandCount) {
838b8f191e0SAiden Grossman   LLVMContext C;
839b8f191e0SAiden Grossman   std::unique_ptr<Module> M = makeLLVMModule(C,
840b8f191e0SAiden Grossman                                              R"IR(
841b8f191e0SAiden Grossman @a = global i64 1
842b8f191e0SAiden Grossman 
843b8f191e0SAiden Grossman define i64 @f1(i64 %e) {
844b8f191e0SAiden Grossman 	%b = load i64, i64* @a
845b8f191e0SAiden Grossman   %c = add i64 %b, 2
846b8f191e0SAiden Grossman   %d = call i64 asm "mov $1,$0", "=r,r" (i64 %c)
847b8f191e0SAiden Grossman 	%f = add i64 %d, %e
848b8f191e0SAiden Grossman 	ret i64 %f
849b8f191e0SAiden Grossman }
850b8f191e0SAiden Grossman )IR");
851b8f191e0SAiden Grossman 
852b8f191e0SAiden Grossman   Function *F1 = M->getFunction("f1");
853b8f191e0SAiden Grossman   EnableDetailedFunctionProperties.setValue(true);
854b8f191e0SAiden Grossman   FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);
855b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithSingleSuccessor, 0);
856b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithTwoSuccessors, 0);
857b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithMoreThanTwoSuccessors, 0);
858b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithSinglePredecessor, 0);
859b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithTwoPredecessors, 0);
860b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.BasicBlocksWithMoreThanTwoPredecessors, 0);
861b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.BigBasicBlocks, 0);
862b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.MediumBasicBlocks, 0);
863b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.SmallBasicBlocks, 1);
864b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.CastInstructionCount, 0);
865b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.FloatingPointInstructionCount, 0);
866b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.IntegerInstructionCount, 4);
867b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.ConstantIntOperandCount, 1);
868b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.ConstantFPOperandCount, 0);
869b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.ConstantOperandCount, 0);
870b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.InstructionOperandCount, 4);
871b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.BasicBlockOperandCount, 0);
872b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.GlobalValueOperandCount, 1);
873b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.InlineAsmOperandCount, 1);
874b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.ArgumentOperandCount, 1);
875b8f191e0SAiden Grossman   EXPECT_EQ(DetailedF1Properties.UnknownOperandCount, 0);
876aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CriticalEdgeCount, 0);
877aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.ControlFlowEdgeCount, 0);
878aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.UnconditionalBranchCount, 0);
879aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.IntrinsicCount, 0);
880aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.DirectCallCount, 1);
881aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.IndirectCallCount, 0);
882aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallReturnsIntegerCount, 1);
883aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallReturnsFloatCount, 0);
884aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallReturnsPointerCount, 0);
885aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallWithManyArgumentsCount, 0);
886aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallWithPointerArgumentCount, 0);
887aad3641eSAiden Grossman   EnableDetailedFunctionProperties.setValue(false);
888aad3641eSAiden Grossman }
889aad3641eSAiden Grossman 
890aad3641eSAiden Grossman TEST_F(FunctionPropertiesAnalysisTest, IntrinsicCount) {
891aad3641eSAiden Grossman   LLVMContext C;
892aad3641eSAiden Grossman   std::unique_ptr<Module> M = makeLLVMModule(C,
893aad3641eSAiden Grossman                                              R"IR(
894aad3641eSAiden Grossman define float @f1(float %a) {
895aad3641eSAiden Grossman   %b = call float @llvm.cos.f32(float %a)
896aad3641eSAiden Grossman   ret float %b
897aad3641eSAiden Grossman }
898aad3641eSAiden Grossman declare float @llvm.cos.f32(float)
899aad3641eSAiden Grossman )IR");
900aad3641eSAiden Grossman 
901aad3641eSAiden Grossman   Function *F1 = M->getFunction("f1");
902aad3641eSAiden Grossman   EnableDetailedFunctionProperties.setValue(true);
903aad3641eSAiden Grossman   FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);
904aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.IntrinsicCount, 1);
905aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.DirectCallCount, 1);
906aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.IndirectCallCount, 0);
907aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallReturnsIntegerCount, 0);
908aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallReturnsFloatCount, 1);
909aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallReturnsPointerCount, 0);
910aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallWithManyArgumentsCount, 0);
911aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallWithPointerArgumentCount, 0);
912aad3641eSAiden Grossman   EnableDetailedFunctionProperties.setValue(false);
913aad3641eSAiden Grossman }
914aad3641eSAiden Grossman 
915aad3641eSAiden Grossman TEST_F(FunctionPropertiesAnalysisTest, FunctionCallMetrics) {
916aad3641eSAiden Grossman   LLVMContext C;
917aad3641eSAiden Grossman   std::unique_ptr<Module> M = makeLLVMModule(C,
918aad3641eSAiden Grossman                                              R"IR(
919aad3641eSAiden Grossman define i64 @f1(i64 %a) {
920aad3641eSAiden Grossman   %b = call i64 @f2(i64 %a, i64 %a, i64 %a, i64 %a, i64 %a)
921aad3641eSAiden Grossman   %c = call ptr @f3()
922aad3641eSAiden Grossman   call void @f4(ptr %c)
923aad3641eSAiden Grossman   %d = call float @f5()
924aad3641eSAiden Grossman   %e = call i64 %c(i64 %b)
925aad3641eSAiden Grossman   ret i64 %b
926aad3641eSAiden Grossman }
927aad3641eSAiden Grossman 
928aad3641eSAiden Grossman declare i64 @f2(i64,i64,i64,i64,i64)
929aad3641eSAiden Grossman declare ptr @f3()
930aad3641eSAiden Grossman declare void @f4(ptr)
931aad3641eSAiden Grossman declare float @f5()
932aad3641eSAiden Grossman )IR");
933aad3641eSAiden Grossman 
934aad3641eSAiden Grossman   Function *F1 = M->getFunction("f1");
935aad3641eSAiden Grossman   EnableDetailedFunctionProperties.setValue(true);
936aad3641eSAiden Grossman   FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);
937aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.IntrinsicCount, 0);
938aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.DirectCallCount, 4);
939aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.IndirectCallCount, 1);
940aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallReturnsIntegerCount, 2);
941aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallReturnsFloatCount, 1);
942aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallReturnsPointerCount, 1);
943aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallWithManyArgumentsCount, 1);
944aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallWithPointerArgumentCount, 1);
945aad3641eSAiden Grossman   EnableDetailedFunctionProperties.setValue(false);
946aad3641eSAiden Grossman }
947aad3641eSAiden Grossman 
948aad3641eSAiden Grossman TEST_F(FunctionPropertiesAnalysisTest, CriticalEdge) {
949aad3641eSAiden Grossman   LLVMContext C;
950aad3641eSAiden Grossman   std::unique_ptr<Module> M = makeLLVMModule(C,
951aad3641eSAiden Grossman                                              R"IR(
952aad3641eSAiden Grossman define i64 @f1(i64 %a) {
953aad3641eSAiden Grossman   %b = icmp eq i64 %a, 1
954aad3641eSAiden Grossman   br i1 %b, label %TopBlock1, label %TopBlock2
955aad3641eSAiden Grossman TopBlock1:
956aad3641eSAiden Grossman   %c = add i64 %a, 1
957aad3641eSAiden Grossman   %e = icmp eq i64 %c, 2
958aad3641eSAiden Grossman   br i1 %e, label %BottomBlock1, label %BottomBlock2
959aad3641eSAiden Grossman TopBlock2:
960aad3641eSAiden Grossman   %d = add i64 %a, 2
961aad3641eSAiden Grossman   br label %BottomBlock2
962aad3641eSAiden Grossman BottomBlock1:
963aad3641eSAiden Grossman   ret i64 0
964aad3641eSAiden Grossman BottomBlock2:
965aad3641eSAiden Grossman   %f = phi i64 [ %c, %TopBlock1 ], [ %d, %TopBlock2 ]
966aad3641eSAiden Grossman   ret i64 %f
967aad3641eSAiden Grossman }
968aad3641eSAiden Grossman )IR");
969aad3641eSAiden Grossman 
970aad3641eSAiden Grossman   Function *F1 = M->getFunction("f1");
971aad3641eSAiden Grossman   EnableDetailedFunctionProperties.setValue(true);
972aad3641eSAiden Grossman   FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);
973aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CriticalEdgeCount, 1);
974aad3641eSAiden Grossman   EnableDetailedFunctionProperties.setValue(false);
975aad3641eSAiden Grossman }
976aad3641eSAiden Grossman 
977aad3641eSAiden Grossman 
978aad3641eSAiden Grossman TEST_F(FunctionPropertiesAnalysisTest, FunctionReturnVectors) {
979aad3641eSAiden Grossman   LLVMContext C;
980aad3641eSAiden Grossman   std::unique_ptr<Module> M = makeLLVMModule(C,
981aad3641eSAiden Grossman                                              R"IR(
982aad3641eSAiden Grossman define <4 x i64> @f1(<4 x i64> %a) {
983aad3641eSAiden Grossman   %b = call <4 x i64> @f2()
984aad3641eSAiden Grossman   %c = call <4 x float> @f3()
985aad3641eSAiden Grossman   %d = call <4 x ptr> @f4()
986aad3641eSAiden Grossman   ret <4 x i64> %b
987aad3641eSAiden Grossman }
988aad3641eSAiden Grossman 
989aad3641eSAiden Grossman declare <4 x i64> @f2()
990aad3641eSAiden Grossman declare <4 x float> @f3()
991aad3641eSAiden Grossman declare <4 x ptr> @f4()
992aad3641eSAiden Grossman )IR");
993aad3641eSAiden Grossman 
994aad3641eSAiden Grossman   Function *F1 = M->getFunction("f1");
995aad3641eSAiden Grossman   EnableDetailedFunctionProperties.setValue(true);
996aad3641eSAiden Grossman   FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);
997aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallReturnsVectorIntCount, 1);
998aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallReturnsVectorFloatCount, 1);
999aad3641eSAiden Grossman   EXPECT_EQ(DetailedF1Properties.CallReturnsVectorPointerCount, 1);
1000b8f191e0SAiden Grossman   EnableDetailedFunctionProperties.setValue(false);
1001b8f191e0SAiden Grossman }
1002*1991aa6bSMircea Trofin 
1003*1991aa6bSMircea Trofin TEST_F(FunctionPropertiesAnalysisTest, ReAddEdges) {
1004*1991aa6bSMircea Trofin   LLVMContext C;
1005*1991aa6bSMircea Trofin   std::unique_ptr<Module> M = makeLLVMModule(C, R"IR(
1006*1991aa6bSMircea Trofin define hidden void @f1(ptr noundef %destatep, i32 noundef %offset, i8 noundef zeroext %byte1) {
1007*1991aa6bSMircea Trofin entry:
1008*1991aa6bSMircea Trofin   %cmp = icmp eq i8 %byte1, 0
1009*1991aa6bSMircea Trofin   br i1 %cmp, label %if.then, label %if.else
1010*1991aa6bSMircea Trofin 
1011*1991aa6bSMircea Trofin if.then:                                          ; preds = %entry
1012*1991aa6bSMircea Trofin   call fastcc void @f2(ptr noundef %destatep, i32 noundef 37, i32 noundef 600)
1013*1991aa6bSMircea Trofin   %and = and i32 %offset, 3
1014*1991aa6bSMircea Trofin   switch i32 %and, label %default.unreachable [
1015*1991aa6bSMircea Trofin     i32 0, label %sw.bb
1016*1991aa6bSMircea Trofin     i32 1, label %sw.bb1
1017*1991aa6bSMircea Trofin     i32 2, label %sw.bb1
1018*1991aa6bSMircea Trofin     i32 3, label %if.end
1019*1991aa6bSMircea Trofin   ]
1020*1991aa6bSMircea Trofin 
1021*1991aa6bSMircea Trofin sw.bb:                                            ; preds = %if.then
1022*1991aa6bSMircea Trofin   call fastcc void @f2(ptr noundef %destatep, i32 noundef 57, i32 noundef 600)
1023*1991aa6bSMircea Trofin   br label %if.end
1024*1991aa6bSMircea Trofin 
1025*1991aa6bSMircea Trofin sw.bb1:                                           ; preds = %if.then, %if.then
1026*1991aa6bSMircea Trofin   call fastcc void @f2(ptr noundef %destatep, i32 noundef 56, i32 noundef 600) #34
1027*1991aa6bSMircea Trofin   br label %if.end
1028*1991aa6bSMircea Trofin 
1029*1991aa6bSMircea Trofin default.unreachable:                              ; preds = %if.then
1030*1991aa6bSMircea Trofin   unreachable
1031*1991aa6bSMircea Trofin 
1032*1991aa6bSMircea Trofin if.else:                                          ; preds = %entry
1033*1991aa6bSMircea Trofin   call fastcc void @f2(ptr noundef %destatep, i32 noundef 56, i32 noundef 600)
1034*1991aa6bSMircea Trofin   br label %if.end
1035*1991aa6bSMircea Trofin 
1036*1991aa6bSMircea Trofin if.end:                                           ; preds = %sw.bb, %sw.bb1, %if.then, %if.else
1037*1991aa6bSMircea Trofin   ret void
1038*1991aa6bSMircea Trofin }
1039*1991aa6bSMircea Trofin 
1040*1991aa6bSMircea Trofin define internal fastcc void @f2(ptr nocapture noundef %destatep, i32 noundef %r_enc, i32 noundef %whack) {
1041*1991aa6bSMircea Trofin entry:
1042*1991aa6bSMircea Trofin   %enc_prob = getelementptr inbounds nuw i8, ptr %destatep, i32 512
1043*1991aa6bSMircea Trofin   %arrayidx = getelementptr inbounds [67 x i32], ptr %enc_prob, i32 0, i32 %r_enc
1044*1991aa6bSMircea Trofin   %0 = load i32, ptr %arrayidx, align 4
1045*1991aa6bSMircea Trofin   %sub = sub nsw i32 %0, %whack
1046*1991aa6bSMircea Trofin   store i32 %sub, ptr %arrayidx, align 4
1047*1991aa6bSMircea Trofin   ret void
1048*1991aa6bSMircea Trofin }
1049*1991aa6bSMircea Trofin   )IR");
1050*1991aa6bSMircea Trofin   auto *F1 = M->getFunction("f1");
1051*1991aa6bSMircea Trofin   auto *F2 = M->getFunction("f2");
1052*1991aa6bSMircea Trofin   auto *CB = [&]() -> CallBase * {
1053*1991aa6bSMircea Trofin     for (auto &BB : *F1)
1054*1991aa6bSMircea Trofin       for (auto &I : BB)
1055*1991aa6bSMircea Trofin         if (auto *CB = dyn_cast<CallBase>(&I);
1056*1991aa6bSMircea Trofin             CB && CB->getCalledFunction() && CB->getCalledFunction() == F2)
1057*1991aa6bSMircea Trofin           return CB;
1058*1991aa6bSMircea Trofin     return nullptr;
1059*1991aa6bSMircea Trofin   }();
1060*1991aa6bSMircea Trofin   ASSERT_NE(CB, nullptr);
1061*1991aa6bSMircea Trofin   auto FPI = buildFPI(*F1);
1062*1991aa6bSMircea Trofin   FunctionPropertiesUpdater FPU(FPI, *CB);
1063*1991aa6bSMircea Trofin   InlineFunctionInfo IFI;
1064*1991aa6bSMircea Trofin   auto IR = llvm::InlineFunction(*CB, IFI);
1065*1991aa6bSMircea Trofin   EXPECT_TRUE(IR.isSuccess());
1066*1991aa6bSMircea Trofin   invalidate(*F1);
1067*1991aa6bSMircea Trofin   EXPECT_TRUE(FPU.finishAndTest(FAM));
1068*1991aa6bSMircea Trofin }
1069*1991aa6bSMircea Trofin 
1070*1991aa6bSMircea Trofin TEST_F(FunctionPropertiesAnalysisTest, InvokeLandingCanStillBeReached) {
1071*1991aa6bSMircea Trofin   LLVMContext C;
1072*1991aa6bSMircea Trofin   // %lpad is reachable from a block not involved in the inlining decision. We
1073*1991aa6bSMircea Trofin   // make sure that's not the entry - otherwise the DT will be recomputed from
1074*1991aa6bSMircea Trofin   // scratch. The idea here is that the edge known to the inliner to potentially
1075*1991aa6bSMircea Trofin   // disappear - %lpad->%ehcleanup -should survive because it is still reachable
1076*1991aa6bSMircea Trofin   // from %middle.
1077*1991aa6bSMircea Trofin   std::unique_ptr<Module> M = makeLLVMModule(C,
1078*1991aa6bSMircea Trofin                                              R"IR(
1079*1991aa6bSMircea Trofin target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
1080*1991aa6bSMircea Trofin target triple = "x86_64-pc-linux-gnu"
1081*1991aa6bSMircea Trofin 
1082*1991aa6bSMircea Trofin define i64 @f1(i32 noundef %value) {
1083*1991aa6bSMircea Trofin entry:
1084*1991aa6bSMircea Trofin   br label %middle
1085*1991aa6bSMircea Trofin middle:
1086*1991aa6bSMircea Trofin   %c = icmp eq i32 %value, 0
1087*1991aa6bSMircea Trofin   br i1 %c, label %invoke, label %lpad
1088*1991aa6bSMircea Trofin invoke:
1089*1991aa6bSMircea Trofin   invoke fastcc void @f2() to label %cont unwind label %lpad
1090*1991aa6bSMircea Trofin cont:
1091*1991aa6bSMircea Trofin   br label %exit
1092*1991aa6bSMircea Trofin lpad:
1093*1991aa6bSMircea Trofin   %lp = landingpad i32 cleanup
1094*1991aa6bSMircea Trofin   br label %ehcleanup
1095*1991aa6bSMircea Trofin ehcleanup:
1096*1991aa6bSMircea Trofin   resume i32 0
1097*1991aa6bSMircea Trofin exit:
1098*1991aa6bSMircea Trofin   ret i64 1
1099*1991aa6bSMircea Trofin }
1100*1991aa6bSMircea Trofin define void @f2() {
1101*1991aa6bSMircea Trofin   ret void
1102*1991aa6bSMircea Trofin }
1103*1991aa6bSMircea Trofin )IR");
1104*1991aa6bSMircea Trofin 
1105*1991aa6bSMircea Trofin   Function *F1 = M->getFunction("f1");
1106*1991aa6bSMircea Trofin   CallBase *CB = findCall(*F1);
1107*1991aa6bSMircea Trofin   EXPECT_NE(CB, nullptr);
1108*1991aa6bSMircea Trofin 
1109*1991aa6bSMircea Trofin   auto FPI = buildFPI(*F1);
1110*1991aa6bSMircea Trofin   FunctionPropertiesUpdater FPU(FPI, *CB);
1111*1991aa6bSMircea Trofin   InlineFunctionInfo IFI;
1112*1991aa6bSMircea Trofin   auto IR = llvm::InlineFunction(*CB, IFI);
1113*1991aa6bSMircea Trofin   EXPECT_TRUE(IR.isSuccess());
1114*1991aa6bSMircea Trofin   invalidate(*F1);
1115*1991aa6bSMircea Trofin   EXPECT_TRUE(FPU.finishAndTest(FAM));
1116*1991aa6bSMircea Trofin }
111706283661STarindu Jayatilaka } // end anonymous namespace
1118