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