1 //===- FunctionPropertiesAnalysisTest.cpp - Function Properties Unit Tests-===//
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
7 //===----------------------------------------------------------------------===//
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"
28 extern cl::opt
<bool> EnableDetailedFunctionProperties
;
29 extern cl::opt
<bool> BigBasicBlockInstructionThreshold
;
30 extern cl::opt
<bool> MediumBasicBlockInstrutionThreshold
;
35 class FunctionPropertiesAnalysisTest
: public testing::Test
{
37 FunctionPropertiesAnalysisTest() {
38 FAM
.registerPass([&] { return DominatorTreeAnalysis(); });
39 FAM
.registerPass([&] { return LoopAnalysis(); });
40 FAM
.registerPass([&] { return PassInstrumentationAnalysis(); });
44 std::unique_ptr
<DominatorTree
> DT
;
45 std::unique_ptr
<LoopInfo
> LI
;
46 FunctionAnalysisManager FAM
;
48 FunctionPropertiesInfo
buildFPI(Function
&F
) {
49 return FunctionPropertiesInfo::getFunctionPropertiesInfo(F
, FAM
);
52 void invalidate(Function
&F
) {
53 PreservedAnalyses PA
= PreservedAnalyses::none();
54 FAM
.invalidate(F
, PA
);
57 std::unique_ptr
<Module
> makeLLVMModule(LLVMContext
&C
, const char *IR
) {
59 std::unique_ptr
<Module
> Mod
= parseAssemblyString(IR
, Err
, C
);
61 Err
.print("MLAnalysisTests", errs());
65 CallBase
* findCall(Function
& F
, const char* Name
= nullptr) {
68 if (auto *CB
= dyn_cast
<CallBase
>(&I
))
69 if (!Name
|| CB
->getName() == Name
)
75 TEST_F(FunctionPropertiesAnalysisTest
, BasicTest
) {
77 std::unique_ptr
<Module
> M
= makeLLVMModule(C
,
79 target datalayout = "e
-m
:e
-i64
:64-f80
:128-n8
:16:32:64-S128
"
80 target triple = "x86_64
-pc
-linux
-gnu
"
83 define i32 @branches(i32) {
84 %cond = icmp slt i32 %0, 3
85 br i1 %cond, label %then, label %else
87 %ret.1 = call i32 @f1(i32 %0)
90 %ret.2 = call i32 @f2(i32 %0)
93 %ret = phi i32 [%ret.1, %then], [%ret.2, %else]
96 define internal i32 @top() {
97 %1 = call i32 @branches(i32 2)
98 %2 = call i32 @f1(i32 %1)
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);
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);
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);
164 TEST_F(FunctionPropertiesAnalysisTest
, DifferentPredecessorSuccessorCounts
) {
166 std::unique_ptr
<Module
> M
= makeLLVMModule(C
,
169 br i1 0, label %br1, label %finally
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);
215 TEST_F(FunctionPropertiesAnalysisTest
, InlineSameBBSimple
) {
217 std::unique_ptr
<Module
> M
= makeLLVMModule(C
,
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)
227 define i32 @f2(i32 %a) {
233 Function
*F1
= M
->getFunction("f1");
234 CallBase
* CB
= findCall(*F1
, "b");
235 EXPECT_NE(CB
, nullptr);
237 FunctionPropertiesInfo ExpectedInitial
;
238 ExpectedInitial
.BasicBlockCount
= 1;
239 ExpectedInitial
.TotalInstructionCount
= 3;
240 ExpectedInitial
.Uses
= 1;
241 ExpectedInitial
.DirectCallsToDefinedFunctions
= 1;
243 FunctionPropertiesInfo ExpectedFinal
= ExpectedInitial
;
244 ExpectedFinal
.DirectCallsToDefinedFunctions
= 0;
246 auto FPI
= buildFPI(*F1
);
247 EXPECT_EQ(FPI
, ExpectedInitial
);
249 FunctionPropertiesUpdater
FPU(FPI
, *CB
);
250 InlineFunctionInfo IFI
;
251 auto IR
= llvm::InlineFunction(*CB
, IFI
);
252 EXPECT_TRUE(IR
.isSuccess());
254 EXPECT_TRUE(FPU
.finishAndTest(FAM
));
255 EXPECT_EQ(FPI
, ExpectedFinal
);
258 TEST_F(FunctionPropertiesAnalysisTest
, InlineSameBBLargerCFG
) {
260 std::unique_ptr
<Module
> M
= makeLLVMModule(C
,
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) {
266 %i = icmp slt i32 %a, 0
267 br i1 %i, label %if.then, label %if.else
269 %b = call i32 @f2(i32 %a)
276 %ret = phi i32 [%c1, %if.then],[%c2, %if.else]
280 define i32 @f2(i32 %a) {
286 Function
*F1
= M
->getFunction("f1");
287 CallBase
* CB
= findCall(*F1
, "b");
288 EXPECT_NE(CB
, nullptr);
290 FunctionPropertiesInfo ExpectedInitial
;
291 ExpectedInitial
.BasicBlockCount
= 4;
292 ExpectedInitial
.BlocksReachedFromConditionalInstruction
= 2;
293 ExpectedInitial
.TotalInstructionCount
= 9;
294 ExpectedInitial
.Uses
= 1;
295 ExpectedInitial
.DirectCallsToDefinedFunctions
= 1;
297 FunctionPropertiesInfo ExpectedFinal
= ExpectedInitial
;
298 ExpectedFinal
.DirectCallsToDefinedFunctions
= 0;
300 auto FPI
= buildFPI(*F1
);
301 EXPECT_EQ(FPI
, ExpectedInitial
);
303 FunctionPropertiesUpdater
FPU(FPI
, *CB
);
304 InlineFunctionInfo IFI
;
305 auto IR
= llvm::InlineFunction(*CB
, IFI
);
306 EXPECT_TRUE(IR
.isSuccess());
308 EXPECT_TRUE(FPU
.finishAndTest(FAM
));
309 EXPECT_EQ(FPI
, ExpectedFinal
);
312 TEST_F(FunctionPropertiesAnalysisTest
, InlineSameBBLoops
) {
314 std::unique_ptr
<Module
> M
= makeLLVMModule(C
,
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) {
320 %i = icmp slt i32 %a, 0
321 br i1 %i, label %if.then, label %if.else
323 %b = call i32 @f2(i32 %a)
330 %ret = phi i32 [%c1, %if.then],[%c2, %if.else]
334 define i32 @f2(i32 %a) {
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
348 Function
*F1
= M
->getFunction("f1");
349 CallBase
* CB
= findCall(*F1
, "b");
350 EXPECT_NE(CB
, nullptr);
352 FunctionPropertiesInfo ExpectedInitial
;
353 ExpectedInitial
.BasicBlockCount
= 4;
354 ExpectedInitial
.BlocksReachedFromConditionalInstruction
= 2;
355 ExpectedInitial
.TotalInstructionCount
= 9;
356 ExpectedInitial
.Uses
= 1;
357 ExpectedInitial
.DirectCallsToDefinedFunctions
= 1;
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;
367 auto FPI
= buildFPI(*F1
);
368 EXPECT_EQ(FPI
, ExpectedInitial
);
369 FunctionPropertiesUpdater
FPU(FPI
, *CB
);
370 InlineFunctionInfo IFI
;
372 auto IR
= llvm::InlineFunction(*CB
, IFI
);
373 EXPECT_TRUE(IR
.isSuccess());
375 EXPECT_TRUE(FPU
.finishAndTest(FAM
));
376 EXPECT_EQ(FPI
, ExpectedFinal
);
379 TEST_F(FunctionPropertiesAnalysisTest
, InvokeSimple
) {
381 std::unique_ptr
<Module
> M
= makeLLVMModule(C
,
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()
387 define internal void @callee() {
389 call void @might_throw()
393 define i32 @caller() personality i32 (...)* @__gxx_personality_v0 {
395 invoke void @callee()
396 to label %cont unwind label %exc
402 %exn = landingpad {i8*, i32}
407 declare i32 @__gxx_personality_v0(...)
410 Function
*F1
= M
->getFunction("caller");
411 CallBase
* CB
= findCall(*F1
);
412 EXPECT_NE(CB
, nullptr);
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());
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());
426 TEST_F(FunctionPropertiesAnalysisTest
, InvokeUnreachableHandler
) {
428 std::unique_ptr
<Module
> M
= makeLLVMModule(C
,
430 declare void @might_throw()
432 define internal i32 @callee() personality i32 (...)* @__gxx_personality_v0 {
434 invoke void @might_throw()
435 to label %cont unwind label %exc
441 %exn = landingpad {i8*, i32}
443 resume { i8*, i32 } %exn
446 define i32 @caller() personality i32 (...)* @__gxx_personality_v0 {
448 %X = invoke i32 @callee()
449 to label %cont unwind label %Handler
455 %exn = landingpad {i8*, i32}
460 declare i32 @__gxx_personality_v0(...)
463 Function
*F1
= M
->getFunction("caller");
464 CallBase
* CB
= findCall(*F1
);
465 EXPECT_NE(CB
, nullptr);
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());
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
));
480 TEST_F(FunctionPropertiesAnalysisTest
, Rethrow
) {
482 std::unique_ptr
<Module
> M
= makeLLVMModule(C
,
484 declare void @might_throw()
486 define internal i32 @callee() personality i32 (...)* @__gxx_personality_v0 {
488 invoke void @might_throw()
489 to label %cont unwind label %exc
495 %exn = landingpad {i8*, i32}
497 resume { i8*, i32 } %exn
500 define i32 @caller() personality i32 (...)* @__gxx_personality_v0 {
502 %X = invoke i32 @callee()
503 to label %cont unwind label %Handler
509 %exn = landingpad {i8*, i32}
514 declare i32 @__gxx_personality_v0(...)
517 Function
*F1
= M
->getFunction("caller");
518 CallBase
* CB
= findCall(*F1
);
519 EXPECT_NE(CB
, nullptr);
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());
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
));
534 TEST_F(FunctionPropertiesAnalysisTest
, LPadChanges
) {
536 std::unique_ptr
<Module
> M
= makeLLVMModule(C
,
538 declare void @external_func()
540 @exception_type1 = external global i8
541 @exception_type2 = external global i8
544 define internal void @inner() personality i8* null {
545 invoke void @external_func()
546 to label %cont unwind label %lpad
551 catch i8* @exception_type1
555 define void @outer() personality i8* null {
557 to label %cont unwind label %lpad
563 catch i8* @exception_type2
569 Function
*F1
= M
->getFunction("outer");
570 CallBase
* CB
= findCall(*F1
);
571 EXPECT_NE(CB
, nullptr);
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());
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
));
586 TEST_F(FunctionPropertiesAnalysisTest
, LPadChangesConditional
) {
588 std::unique_ptr
<Module
> M
= makeLLVMModule(C
,
590 declare void @external_func()
592 @exception_type1 = external global i8
593 @exception_type2 = external global i8
596 define internal void @inner() personality i8* null {
597 invoke void @external_func()
598 to label %cont unwind label %lpad
603 catch i8* @exception_type1
607 define void @outer(i32 %a) personality i8* null {
609 %i = icmp slt i32 %a, 0
610 br i1 %i, label %if.then, label %cont
613 to label %cont unwind label %lpad
619 catch i8* @exception_type2
625 Function
*F1
= M
->getFunction("outer");
626 CallBase
* CB
= findCall(*F1
);
627 EXPECT_NE(CB
, nullptr);
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());
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
));
642 TEST_F(FunctionPropertiesAnalysisTest
, InlineSameLoopBB
) {
644 std::unique_ptr
<Module
> M
= makeLLVMModule(C
,
646 target datalayout = "e
-m
:e
-i64
:64-f80
:128-n8
:16:32:64-S128
"
647 target triple = "x86_64
-pc
-linux
-gnu
"
652 define i32 @f1(i32 %a) {
656 %i = call i32 @f2(i32 %a)
657 %c = icmp slt i32 %i, %a
658 br i1 %c, label %loop, label %end
660 %r = phi i32 [%i, %loop], [%a, %entry]
664 define i32 @f2(i32 %a) {
665 %cnd = icmp slt i32 %a, 0
666 br i1 %cnd, label %then, label %else
674 %r = phi i32 [%r1, %then], [%r2, %else]
679 Function
*F1
= M
->getFunction("f1");
680 CallBase
*CB
= findCall(*F1
);
681 EXPECT_NE(CB
, nullptr);
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;
692 FunctionPropertiesInfo ExpectedFinal
= ExpectedInitial
;
693 ExpectedFinal
.BasicBlockCount
= 6;
694 ExpectedFinal
.DirectCallsToDefinedFunctions
= 0;
695 ExpectedFinal
.BlocksReachedFromConditionalInstruction
= 4;
696 ExpectedFinal
.TotalInstructionCount
= 12;
698 auto FPI
= buildFPI(*F1
);
699 EXPECT_EQ(FPI
, ExpectedInitial
);
701 FunctionPropertiesUpdater
FPU(FPI
, *CB
);
702 InlineFunctionInfo IFI
;
703 auto IR
= llvm::InlineFunction(*CB
, IFI
);
704 EXPECT_TRUE(IR
.isSuccess());
706 EXPECT_TRUE(FPU
.finishAndTest(FAM
));
707 EXPECT_EQ(FPI
, ExpectedFinal
);
710 TEST_F(FunctionPropertiesAnalysisTest
, Unreachable
) {
712 std::unique_ptr
<Module
> M
= makeLLVMModule(C
,
714 target datalayout = "e
-m
:e
-i64
:64-f80
:128-n8
:16:32:64-S128
"
715 target triple = "x86_64
-pc
-linux
-gnu
"
717 define i64 @f1(i32 noundef %value) {
719 br i1 true, label %cond.true, label %cond.false
721 cond.true: ; preds = %entry
722 %conv2 = sext i32 %value to i64
725 cond.false: ; preds = %entry
726 %call3 = call noundef i64 @f2()
735 cond.end: ; preds = %cond.false, %cond.true
736 %cond = phi i64 [ %conv2, %cond.true ], [ %call3, %extra ]
742 tail call void @llvm.trap()
746 declare void @llvm.trap()
749 Function
*F1
= M
->getFunction("f1");
750 CallBase
*CB
= findCall(*F1
);
751 EXPECT_NE(CB
, nullptr);
753 FunctionPropertiesInfo ExpectedInitial
;
754 ExpectedInitial
.BasicBlockCount
= 6;
755 ExpectedInitial
.TotalInstructionCount
= 9;
756 ExpectedInitial
.BlocksReachedFromConditionalInstruction
= 2;
757 ExpectedInitial
.Uses
= 1;
758 ExpectedInitial
.DirectCallsToDefinedFunctions
= 1;
760 FunctionPropertiesInfo ExpectedFinal
= ExpectedInitial
;
761 ExpectedFinal
.BasicBlockCount
= 4;
762 ExpectedFinal
.DirectCallsToDefinedFunctions
= 0;
763 ExpectedFinal
.TotalInstructionCount
= 7;
765 auto FPI
= buildFPI(*F1
);
766 EXPECT_EQ(FPI
, ExpectedInitial
);
768 FunctionPropertiesUpdater
FPU(FPI
, *CB
);
769 InlineFunctionInfo IFI
;
770 auto IR
= llvm::InlineFunction(*CB
, IFI
);
771 EXPECT_TRUE(IR
.isSuccess());
773 EXPECT_TRUE(FPU
.finishAndTest(FAM
));
774 EXPECT_EQ(FPI
, ExpectedFinal
);
777 TEST_F(FunctionPropertiesAnalysisTest
, InvokeSkipLP
) {
779 std::unique_ptr
<Module
> M
= makeLLVMModule(C
,
781 target datalayout = "e
-m
:e
-i64
:64-f80
:128-n8
:16:32:64-S128
"
782 target triple = "x86_64
-pc
-linux
-gnu
"
784 define i64 @f1(i32 noundef %value) {
786 invoke fastcc void @f2() to label %cont unwind label %lpad
790 %lp = landingpad i32 cleanup
796 invoke noundef void @f3() to label %exit unwind label %lpad
800 %lp = landingpad i32 cleanup
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);
813 FunctionPropertiesInfo ExpectedInitial
;
814 ExpectedInitial
.BasicBlockCount
= 4;
815 ExpectedInitial
.TotalInstructionCount
= 5;
816 ExpectedInitial
.BlocksReachedFromConditionalInstruction
= 0;
817 ExpectedInitial
.Uses
= 1;
818 ExpectedInitial
.DirectCallsToDefinedFunctions
= 1;
820 FunctionPropertiesInfo ExpectedFinal
= ExpectedInitial
;
821 ExpectedFinal
.BasicBlockCount
= 6;
822 ExpectedFinal
.DirectCallsToDefinedFunctions
= 0;
823 ExpectedFinal
.TotalInstructionCount
= 8;
825 auto FPI
= buildFPI(*F1
);
826 EXPECT_EQ(FPI
, ExpectedInitial
);
828 FunctionPropertiesUpdater
FPU(FPI
, *CB
);
829 InlineFunctionInfo IFI
;
830 auto IR
= llvm::InlineFunction(*CB
, IFI
);
831 EXPECT_TRUE(IR
.isSuccess());
833 EXPECT_TRUE(FPU
.finishAndTest(FAM
));
834 EXPECT_EQ(FPI
, ExpectedFinal
);
837 TEST_F(FunctionPropertiesAnalysisTest
, DetailedOperandCount
) {
839 std::unique_ptr
<Module
> M
= makeLLVMModule(C
,
843 define i64 @f1(i64 %e) {
844 %b = load i64, i64* @a
846 %d = call i64 asm "mov $
1,$
0", "=r
,r
" (i64 %c)
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);
890 TEST_F(FunctionPropertiesAnalysisTest
, IntrinsicCount
) {
892 std::unique_ptr
<Module
> M
= makeLLVMModule(C
,
894 define float @f1(float %a) {
895 %b = call float @llvm.cos.f32(float %a)
898 declare float @llvm.cos.f32(float)
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);
915 TEST_F(FunctionPropertiesAnalysisTest
, FunctionCallMetrics
) {
917 std::unique_ptr
<Module
> M
= makeLLVMModule(C
,
919 define i64 @f1(i64 %a) {
920 %b = call i64 @f2(i64 %a, i64 %a, i64 %a, i64 %a, i64 %a)
922 call void @f4(ptr %c)
923 %d = call float @f5()
924 %e = call i64 %c(i64 %b)
928 declare i64 @f2(i64,i64,i64,i64,i64)
930 declare void @f4(ptr)
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);
948 TEST_F(FunctionPropertiesAnalysisTest
, CriticalEdge
) {
950 std::unique_ptr
<Module
> M
= makeLLVMModule(C
,
952 define i64 @f1(i64 %a) {
953 %b = icmp eq i64 %a, 1
954 br i1 %b, label %TopBlock1, label %TopBlock2
957 %e = icmp eq i64 %c, 2
958 br i1 %e, label %BottomBlock1, label %BottomBlock2
961 br label %BottomBlock2
965 %f = phi i64 [ %c, %TopBlock1 ], [ %d, %TopBlock2 ]
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);
978 TEST_F(FunctionPropertiesAnalysisTest
, FunctionReturnVectors
) {
980 std::unique_ptr
<Module
> M
= makeLLVMModule(C
,
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()
989 declare <4 x i64> @f2()
990 declare <4 x float> @f3()
991 declare <4 x ptr> @f4()
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);
1003 TEST_F(FunctionPropertiesAnalysisTest
, ReAddEdges
) {
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) {
1008 %cmp = icmp eq i8 %byte1, 0
1009 br i1 %cmp, label %if.then, label %if.else
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 [
1016 i32 1, label %sw.bb1
1017 i32 2, label %sw.bb1
1018 i32 3, label %if.end
1021 sw.bb: ; preds = %if.then
1022 call fastcc void @f2(ptr noundef %destatep, i32 noundef 57, i32 noundef 600)
1025 sw.bb1: ; preds = %if.then, %if.then
1026 call fastcc void @f2(ptr noundef %destatep, i32 noundef 56, i32 noundef 600) #34
1029 default.unreachable: ; preds = %if.then
1032 if.else: ; preds = %entry
1033 call fastcc void @f2(ptr noundef %destatep, i32 noundef 56, i32 noundef 600)
1036 if.end: ; preds = %sw.bb, %sw.bb1, %if.then, %if.else
1040 define internal fastcc void @f2(ptr nocapture noundef %destatep, i32 noundef %r_enc, i32 noundef %whack) {
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
1050 auto *F1
= M
->getFunction("f1");
1051 auto *F2
= M
->getFunction("f2");
1052 auto *CB
= [&]() -> CallBase
* {
1053 for (auto &BB
: *F1
)
1055 if (auto *CB
= dyn_cast
<CallBase
>(&I
);
1056 CB
&& CB
->getCalledFunction() && CB
->getCalledFunction() == F2
)
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());
1067 EXPECT_TRUE(FPU
.finishAndTest(FAM
));
1070 TEST_F(FunctionPropertiesAnalysisTest
, InvokeLandingCanStillBeReached
) {
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
1077 std::unique_ptr
<Module
> M
= makeLLVMModule(C
,
1079 target datalayout = "e
-m
:e
-i64
:64-f80
:128-n8
:16:32:64-S128
"
1080 target triple = "x86_64
-pc
-linux
-gnu
"
1082 define i64 @f1(i32 noundef %value) {
1086 %c = icmp eq i32 %value, 0
1087 br i1 %c, label %invoke, label %lpad
1089 invoke fastcc void @f2() to label %cont unwind label %lpad
1093 %lp = landingpad i32 cleanup
1105 Function
*F1
= M
->getFunction("f1");
1106 CallBase
*CB
= findCall(*F1
);
1107 EXPECT_NE(CB
, nullptr);
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());
1115 EXPECT_TRUE(FPU
.finishAndTest(FAM
));
1117 } // end anonymous namespace