1 //===- FunctionPropertiesAnalysisTest.cpp - Function Properties Unit Tests-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/Analysis/FunctionPropertiesAnalysis.h" 10 #include "llvm/ADT/iterator_range.h" 11 #include "llvm/Analysis/AliasAnalysis.h" 12 #include "llvm/Analysis/LoopInfo.h" 13 #include "llvm/AsmParser/Parser.h" 14 #include "llvm/IR/Dominators.h" 15 #include "llvm/IR/Instructions.h" 16 #include "llvm/IR/LLVMContext.h" 17 #include "llvm/IR/Module.h" 18 #include "llvm/IR/PassManager.h" 19 #include "llvm/Passes/PassBuilder.h" 20 #include "llvm/Passes/StandardInstrumentations.h" 21 #include "llvm/Support/SourceMgr.h" 22 #include "llvm/Transforms/Utils/Cloning.h" 23 #include "gtest/gtest.h" 24 #include <cstring> 25 26 using namespace llvm; 27 namespace { 28 29 class FunctionPropertiesAnalysisTest : public testing::Test { 30 public: 31 FunctionPropertiesAnalysisTest() { 32 FAM.registerPass([&] { return DominatorTreeAnalysis(); }); 33 FAM.registerPass([&] { return LoopAnalysis(); }); 34 FAM.registerPass([&] { return PassInstrumentationAnalysis(); }); 35 } 36 37 protected: 38 std::unique_ptr<DominatorTree> DT; 39 std::unique_ptr<LoopInfo> LI; 40 FunctionAnalysisManager FAM; 41 42 FunctionPropertiesInfo buildFPI(Function &F) { 43 return FunctionPropertiesInfo::getFunctionPropertiesInfo(F, FAM); 44 } 45 46 void invalidate(Function &F) { 47 PreservedAnalyses PA = PreservedAnalyses::none(); 48 FAM.invalidate(F, PA); 49 } 50 51 std::unique_ptr<Module> makeLLVMModule(LLVMContext &C, const char *IR) { 52 SMDiagnostic Err; 53 std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C); 54 if (!Mod) 55 Err.print("MLAnalysisTests", errs()); 56 return Mod; 57 } 58 59 CallBase* findCall(Function& F, const char* Name = nullptr) { 60 for (auto &BB : F) 61 for (auto &I : BB ) 62 if (auto *CB = dyn_cast<CallBase>(&I)) 63 if (!Name || CB->getName() == Name) 64 return CB; 65 return nullptr; 66 } 67 }; 68 69 TEST_F(FunctionPropertiesAnalysisTest, BasicTest) { 70 LLVMContext C; 71 std::unique_ptr<Module> M = makeLLVMModule(C, 72 R"IR( 73 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 74 target triple = "x86_64-pc-linux-gnu" 75 declare i32 @f1(i32) 76 declare i32 @f2(i32) 77 define i32 @branches(i32) { 78 %cond = icmp slt i32 %0, 3 79 br i1 %cond, label %then, label %else 80 then: 81 %ret.1 = call i32 @f1(i32 %0) 82 br label %last.block 83 else: 84 %ret.2 = call i32 @f2(i32 %0) 85 br label %last.block 86 last.block: 87 %ret = phi i32 [%ret.1, %then], [%ret.2, %else] 88 ret i32 %ret 89 } 90 define internal i32 @top() { 91 %1 = call i32 @branches(i32 2) 92 %2 = call i32 @f1(i32 %1) 93 ret i32 %2 94 } 95 )IR"); 96 97 Function *BranchesFunction = M->getFunction("branches"); 98 FunctionPropertiesInfo BranchesFeatures = buildFPI(*BranchesFunction); 99 EXPECT_EQ(BranchesFeatures.BasicBlockCount, 4); 100 EXPECT_EQ(BranchesFeatures.BlocksReachedFromConditionalInstruction, 2); 101 // 2 Users: top is one. The other is added because @branches is not internal, 102 // so it may have external callers. 103 EXPECT_EQ(BranchesFeatures.Uses, 2); 104 EXPECT_EQ(BranchesFeatures.DirectCallsToDefinedFunctions, 0); 105 EXPECT_EQ(BranchesFeatures.LoadInstCount, 0); 106 EXPECT_EQ(BranchesFeatures.StoreInstCount, 0); 107 EXPECT_EQ(BranchesFeatures.MaxLoopDepth, 0); 108 EXPECT_EQ(BranchesFeatures.TopLevelLoopCount, 0); 109 110 Function *TopFunction = M->getFunction("top"); 111 FunctionPropertiesInfo TopFeatures = buildFPI(*TopFunction); 112 EXPECT_EQ(TopFeatures.BasicBlockCount, 1); 113 EXPECT_EQ(TopFeatures.BlocksReachedFromConditionalInstruction, 0); 114 EXPECT_EQ(TopFeatures.Uses, 0); 115 EXPECT_EQ(TopFeatures.DirectCallsToDefinedFunctions, 1); 116 EXPECT_EQ(BranchesFeatures.LoadInstCount, 0); 117 EXPECT_EQ(BranchesFeatures.StoreInstCount, 0); 118 EXPECT_EQ(BranchesFeatures.MaxLoopDepth, 0); 119 EXPECT_EQ(BranchesFeatures.TopLevelLoopCount, 0); 120 } 121 122 TEST_F(FunctionPropertiesAnalysisTest, InlineSameBBSimple) { 123 LLVMContext C; 124 std::unique_ptr<Module> M = makeLLVMModule(C, 125 R"IR( 126 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 127 target triple = "x86_64-pc-linux-gnu" 128 define i32 @f1(i32 %a) { 129 %b = call i32 @f2(i32 %a) 130 %c = add i32 %b, 2 131 ret i32 %c 132 } 133 134 define i32 @f2(i32 %a) { 135 %b = add i32 %a, 1 136 ret i32 %b 137 } 138 )IR"); 139 140 Function *F1 = M->getFunction("f1"); 141 CallBase* CB = findCall(*F1, "b"); 142 EXPECT_NE(CB, nullptr); 143 144 FunctionPropertiesInfo ExpectedInitial; 145 ExpectedInitial.BasicBlockCount = 1; 146 ExpectedInitial.TotalInstructionCount = 3; 147 ExpectedInitial.Uses = 1; 148 ExpectedInitial.DirectCallsToDefinedFunctions = 1; 149 150 FunctionPropertiesInfo ExpectedFinal = ExpectedInitial; 151 ExpectedFinal.DirectCallsToDefinedFunctions = 0; 152 153 auto FPI = buildFPI(*F1); 154 EXPECT_EQ(FPI, ExpectedInitial); 155 156 FunctionPropertiesUpdater FPU(FPI, *CB); 157 InlineFunctionInfo IFI; 158 auto IR = llvm::InlineFunction(*CB, IFI); 159 EXPECT_TRUE(IR.isSuccess()); 160 invalidate(*F1); 161 FPU.finish(FAM); 162 EXPECT_EQ(FPI, ExpectedFinal); 163 } 164 165 TEST_F(FunctionPropertiesAnalysisTest, InlineSameBBLargerCFG) { 166 LLVMContext C; 167 std::unique_ptr<Module> M = makeLLVMModule(C, 168 R"IR( 169 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 170 target triple = "x86_64-pc-linux-gnu" 171 define i32 @f1(i32 %a) { 172 entry: 173 %i = icmp slt i32 %a, 0 174 br i1 %i, label %if.then, label %if.else 175 if.then: 176 %b = call i32 @f2(i32 %a) 177 %c1 = add i32 %b, 2 178 br label %end 179 if.else: 180 %c2 = add i32 %a, 1 181 br label %end 182 end: 183 %ret = phi i32 [%c1, %if.then],[%c2, %if.else] 184 ret i32 %ret 185 } 186 187 define i32 @f2(i32 %a) { 188 %b = add i32 %a, 1 189 ret i32 %b 190 } 191 )IR"); 192 193 Function *F1 = M->getFunction("f1"); 194 CallBase* CB = findCall(*F1, "b"); 195 EXPECT_NE(CB, nullptr); 196 197 FunctionPropertiesInfo ExpectedInitial; 198 ExpectedInitial.BasicBlockCount = 4; 199 ExpectedInitial.BlocksReachedFromConditionalInstruction = 2; 200 ExpectedInitial.TotalInstructionCount = 9; 201 ExpectedInitial.Uses = 1; 202 ExpectedInitial.DirectCallsToDefinedFunctions = 1; 203 204 FunctionPropertiesInfo ExpectedFinal = ExpectedInitial; 205 ExpectedFinal.DirectCallsToDefinedFunctions = 0; 206 207 auto FPI = buildFPI(*F1); 208 EXPECT_EQ(FPI, ExpectedInitial); 209 210 FunctionPropertiesUpdater FPU(FPI, *CB); 211 InlineFunctionInfo IFI; 212 auto IR = llvm::InlineFunction(*CB, IFI); 213 EXPECT_TRUE(IR.isSuccess()); 214 invalidate(*F1); 215 FPU.finish(FAM); 216 EXPECT_EQ(FPI, ExpectedFinal); 217 } 218 219 TEST_F(FunctionPropertiesAnalysisTest, InlineSameBBLoops) { 220 LLVMContext C; 221 std::unique_ptr<Module> M = makeLLVMModule(C, 222 R"IR( 223 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 224 target triple = "x86_64-pc-linux-gnu" 225 define i32 @f1(i32 %a) { 226 entry: 227 %i = icmp slt i32 %a, 0 228 br i1 %i, label %if.then, label %if.else 229 if.then: 230 %b = call i32 @f2(i32 %a) 231 %c1 = add i32 %b, 2 232 br label %end 233 if.else: 234 %c2 = add i32 %a, 1 235 br label %end 236 end: 237 %ret = phi i32 [%c1, %if.then],[%c2, %if.else] 238 ret i32 %ret 239 } 240 241 define i32 @f2(i32 %a) { 242 entry: 243 br label %loop 244 loop: 245 %indvar = phi i32 [%indvar.next, %loop], [0, %entry] 246 %b = add i32 %a, %indvar 247 %indvar.next = add i32 %indvar, 1 248 %cond = icmp slt i32 %indvar.next, %a 249 br i1 %cond, label %loop, label %exit 250 exit: 251 ret i32 %b 252 } 253 )IR"); 254 255 Function *F1 = M->getFunction("f1"); 256 CallBase* CB = findCall(*F1, "b"); 257 EXPECT_NE(CB, nullptr); 258 259 FunctionPropertiesInfo ExpectedInitial; 260 ExpectedInitial.BasicBlockCount = 4; 261 ExpectedInitial.BlocksReachedFromConditionalInstruction = 2; 262 ExpectedInitial.TotalInstructionCount = 9; 263 ExpectedInitial.Uses = 1; 264 ExpectedInitial.DirectCallsToDefinedFunctions = 1; 265 266 FunctionPropertiesInfo ExpectedFinal; 267 ExpectedFinal.BasicBlockCount = 6; 268 ExpectedFinal.BlocksReachedFromConditionalInstruction = 4; 269 ExpectedFinal.Uses = 1; 270 ExpectedFinal.MaxLoopDepth = 1; 271 ExpectedFinal.TopLevelLoopCount = 1; 272 ExpectedFinal.TotalInstructionCount = 14; 273 274 auto FPI = buildFPI(*F1); 275 EXPECT_EQ(FPI, ExpectedInitial); 276 FunctionPropertiesUpdater FPU(FPI, *CB); 277 InlineFunctionInfo IFI; 278 279 auto IR = llvm::InlineFunction(*CB, IFI); 280 EXPECT_TRUE(IR.isSuccess()); 281 invalidate(*F1); 282 FPU.finish(FAM); 283 EXPECT_EQ(FPI, ExpectedFinal); 284 } 285 286 TEST_F(FunctionPropertiesAnalysisTest, InvokeSimple) { 287 LLVMContext C; 288 std::unique_ptr<Module> M = makeLLVMModule(C, 289 R"IR( 290 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 291 target triple = "x86_64-pc-linux-gnu" 292 declare void @might_throw() 293 294 define internal void @callee() { 295 entry: 296 call void @might_throw() 297 ret void 298 } 299 300 define i32 @caller() personality i32 (...)* @__gxx_personality_v0 { 301 entry: 302 invoke void @callee() 303 to label %cont unwind label %exc 304 305 cont: 306 ret i32 0 307 308 exc: 309 %exn = landingpad {i8*, i32} 310 cleanup 311 ret i32 1 312 } 313 314 declare i32 @__gxx_personality_v0(...) 315 )IR"); 316 317 Function *F1 = M->getFunction("caller"); 318 CallBase* CB = findCall(*F1); 319 EXPECT_NE(CB, nullptr); 320 321 auto FPI = buildFPI(*F1); 322 FunctionPropertiesUpdater FPU(FPI, *CB); 323 InlineFunctionInfo IFI; 324 auto IR = llvm::InlineFunction(*CB, IFI); 325 EXPECT_TRUE(IR.isSuccess()); 326 invalidate(*F1); 327 FPU.finish(FAM); 328 EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size()); 329 EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount), 330 F1->getInstructionCount()); 331 } 332 333 TEST_F(FunctionPropertiesAnalysisTest, InvokeUnreachableHandler) { 334 LLVMContext C; 335 std::unique_ptr<Module> M = makeLLVMModule(C, 336 R"IR( 337 declare void @might_throw() 338 339 define internal i32 @callee() personality i32 (...)* @__gxx_personality_v0 { 340 entry: 341 invoke void @might_throw() 342 to label %cont unwind label %exc 343 344 cont: 345 ret i32 0 346 347 exc: 348 %exn = landingpad {i8*, i32} 349 cleanup 350 resume { i8*, i32 } %exn 351 } 352 353 define i32 @caller() personality i32 (...)* @__gxx_personality_v0 { 354 entry: 355 %X = invoke i32 @callee() 356 to label %cont unwind label %Handler 357 358 cont: 359 ret i32 %X 360 361 Handler: 362 %exn = landingpad {i8*, i32} 363 cleanup 364 ret i32 1 365 } 366 367 declare i32 @__gxx_personality_v0(...) 368 )IR"); 369 370 Function *F1 = M->getFunction("caller"); 371 CallBase* CB = findCall(*F1); 372 EXPECT_NE(CB, nullptr); 373 374 auto FPI = buildFPI(*F1); 375 FunctionPropertiesUpdater FPU(FPI, *CB); 376 InlineFunctionInfo IFI; 377 auto IR = llvm::InlineFunction(*CB, IFI); 378 EXPECT_TRUE(IR.isSuccess()); 379 invalidate(*F1); 380 FPU.finish(FAM); 381 EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size() - 1); 382 EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount), 383 F1->getInstructionCount() - 2); 384 EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM)); 385 } 386 387 TEST_F(FunctionPropertiesAnalysisTest, Rethrow) { 388 LLVMContext C; 389 std::unique_ptr<Module> M = makeLLVMModule(C, 390 R"IR( 391 declare void @might_throw() 392 393 define internal i32 @callee() personality i32 (...)* @__gxx_personality_v0 { 394 entry: 395 invoke void @might_throw() 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 resume { i8*, i32 } %exn 405 } 406 407 define i32 @caller() personality i32 (...)* @__gxx_personality_v0 { 408 entry: 409 %X = invoke i32 @callee() 410 to label %cont unwind label %Handler 411 412 cont: 413 ret i32 %X 414 415 Handler: 416 %exn = landingpad {i8*, i32} 417 cleanup 418 ret i32 1 419 } 420 421 declare i32 @__gxx_personality_v0(...) 422 )IR"); 423 424 Function *F1 = M->getFunction("caller"); 425 CallBase* CB = findCall(*F1); 426 EXPECT_NE(CB, nullptr); 427 428 auto FPI = buildFPI(*F1); 429 FunctionPropertiesUpdater FPU(FPI, *CB); 430 InlineFunctionInfo IFI; 431 auto IR = llvm::InlineFunction(*CB, IFI); 432 EXPECT_TRUE(IR.isSuccess()); 433 invalidate(*F1); 434 FPU.finish(FAM); 435 EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size() - 1); 436 EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount), 437 F1->getInstructionCount() - 2); 438 EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM)); 439 } 440 441 TEST_F(FunctionPropertiesAnalysisTest, LPadChanges) { 442 LLVMContext C; 443 std::unique_ptr<Module> M = makeLLVMModule(C, 444 R"IR( 445 declare void @external_func() 446 447 @exception_type1 = external global i8 448 @exception_type2 = external global i8 449 450 451 define internal void @inner() personality i8* null { 452 invoke void @external_func() 453 to label %cont unwind label %lpad 454 cont: 455 ret void 456 lpad: 457 %lp = landingpad i32 458 catch i8* @exception_type1 459 resume i32 %lp 460 } 461 462 define void @outer() personality i8* null { 463 invoke void @inner() 464 to label %cont unwind label %lpad 465 cont: 466 ret void 467 lpad: 468 %lp = landingpad i32 469 cleanup 470 catch i8* @exception_type2 471 resume i32 %lp 472 } 473 474 )IR"); 475 476 Function *F1 = M->getFunction("outer"); 477 CallBase* CB = findCall(*F1); 478 EXPECT_NE(CB, nullptr); 479 480 auto FPI = buildFPI(*F1); 481 FunctionPropertiesUpdater FPU(FPI, *CB); 482 InlineFunctionInfo IFI; 483 auto IR = llvm::InlineFunction(*CB, IFI); 484 EXPECT_TRUE(IR.isSuccess()); 485 invalidate(*F1); 486 FPU.finish(FAM); 487 EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size() - 1); 488 EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount), 489 F1->getInstructionCount() - 2); 490 EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM)); 491 } 492 493 TEST_F(FunctionPropertiesAnalysisTest, LPadChangesConditional) { 494 LLVMContext C; 495 std::unique_ptr<Module> M = makeLLVMModule(C, 496 R"IR( 497 declare void @external_func() 498 499 @exception_type1 = external global i8 500 @exception_type2 = external global i8 501 502 503 define internal void @inner() personality i8* null { 504 invoke void @external_func() 505 to label %cont unwind label %lpad 506 cont: 507 ret void 508 lpad: 509 %lp = landingpad i32 510 catch i8* @exception_type1 511 resume i32 %lp 512 } 513 514 define void @outer(i32 %a) personality i8* null { 515 entry: 516 %i = icmp slt i32 %a, 0 517 br i1 %i, label %if.then, label %cont 518 if.then: 519 invoke void @inner() 520 to label %cont unwind label %lpad 521 cont: 522 ret void 523 lpad: 524 %lp = landingpad i32 525 cleanup 526 catch i8* @exception_type2 527 resume i32 %lp 528 } 529 530 )IR"); 531 532 Function *F1 = M->getFunction("outer"); 533 CallBase* CB = findCall(*F1); 534 EXPECT_NE(CB, nullptr); 535 536 auto FPI = buildFPI(*F1); 537 FunctionPropertiesUpdater FPU(FPI, *CB); 538 InlineFunctionInfo IFI; 539 auto IR = llvm::InlineFunction(*CB, IFI); 540 EXPECT_TRUE(IR.isSuccess()); 541 invalidate(*F1); 542 FPU.finish(FAM); 543 EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size() - 1); 544 EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount), 545 F1->getInstructionCount() - 2); 546 EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM)); 547 } 548 549 TEST_F(FunctionPropertiesAnalysisTest, InlineSameLoopBB) { 550 LLVMContext C; 551 std::unique_ptr<Module> M = makeLLVMModule(C, 552 R"IR( 553 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 554 target triple = "x86_64-pc-linux-gnu" 555 556 declare i32 @a() 557 declare i32 @b() 558 559 define i32 @f1(i32 %a) { 560 entry: 561 br label %loop 562 loop: 563 %i = call i32 @f2(i32 %a) 564 %c = icmp slt i32 %i, %a 565 br i1 %c, label %loop, label %end 566 end: 567 %r = phi i32 [%i, %loop], [%a, %entry] 568 ret i32 %r 569 } 570 571 define i32 @f2(i32 %a) { 572 %cnd = icmp slt i32 %a, 0 573 br i1 %cnd, label %then, label %else 574 then: 575 %r1 = call i32 @a() 576 br label %end 577 else: 578 %r2 = call i32 @b() 579 br label %end 580 end: 581 %r = phi i32 [%r1, %then], [%r2, %else] 582 ret i32 %r 583 } 584 )IR"); 585 586 Function *F1 = M->getFunction("f1"); 587 CallBase *CB = findCall(*F1); 588 EXPECT_NE(CB, nullptr); 589 590 FunctionPropertiesInfo ExpectedInitial; 591 ExpectedInitial.BasicBlockCount = 3; 592 ExpectedInitial.TotalInstructionCount = 6; 593 ExpectedInitial.BlocksReachedFromConditionalInstruction = 2; 594 ExpectedInitial.Uses = 1; 595 ExpectedInitial.DirectCallsToDefinedFunctions = 1; 596 ExpectedInitial.MaxLoopDepth = 1; 597 ExpectedInitial.TopLevelLoopCount = 1; 598 599 FunctionPropertiesInfo ExpectedFinal = ExpectedInitial; 600 ExpectedFinal.BasicBlockCount = 6; 601 ExpectedFinal.DirectCallsToDefinedFunctions = 0; 602 ExpectedFinal.BlocksReachedFromConditionalInstruction = 4; 603 ExpectedFinal.TotalInstructionCount = 12; 604 605 auto FPI = buildFPI(*F1); 606 EXPECT_EQ(FPI, ExpectedInitial); 607 608 FunctionPropertiesUpdater FPU(FPI, *CB); 609 InlineFunctionInfo IFI; 610 auto IR = llvm::InlineFunction(*CB, IFI); 611 EXPECT_TRUE(IR.isSuccess()); 612 invalidate(*F1); 613 FPU.finish(FAM); 614 EXPECT_EQ(FPI, ExpectedFinal); 615 } 616 617 TEST_F(FunctionPropertiesAnalysisTest, Unreachable) { 618 LLVMContext C; 619 std::unique_ptr<Module> M = makeLLVMModule(C, 620 R"IR( 621 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 622 target triple = "x86_64-pc-linux-gnu" 623 624 define i64 @f1(i32 noundef %value) { 625 entry: 626 br i1 true, label %cond.true, label %cond.false 627 628 cond.true: ; preds = %entry 629 %conv2 = sext i32 %value to i64 630 br label %cond.end 631 632 cond.false: ; preds = %entry 633 %call3 = call noundef i64 @f2() 634 br label %extra 635 636 extra: 637 br label %extra2 638 639 extra2: 640 br label %cond.end 641 642 cond.end: ; preds = %cond.false, %cond.true 643 %cond = phi i64 [ %conv2, %cond.true ], [ %call3, %extra ] 644 ret i64 %cond 645 } 646 647 define i64 @f2() { 648 entry: 649 tail call void @llvm.trap() 650 unreachable 651 } 652 653 declare void @llvm.trap() 654 )IR"); 655 656 Function *F1 = M->getFunction("f1"); 657 CallBase *CB = findCall(*F1); 658 EXPECT_NE(CB, nullptr); 659 660 FunctionPropertiesInfo ExpectedInitial; 661 ExpectedInitial.BasicBlockCount = 6; 662 ExpectedInitial.TotalInstructionCount = 9; 663 ExpectedInitial.BlocksReachedFromConditionalInstruction = 2; 664 ExpectedInitial.Uses = 1; 665 ExpectedInitial.DirectCallsToDefinedFunctions = 1; 666 667 FunctionPropertiesInfo ExpectedFinal = ExpectedInitial; 668 ExpectedFinal.BasicBlockCount = 4; 669 ExpectedFinal.DirectCallsToDefinedFunctions = 0; 670 ExpectedFinal.TotalInstructionCount = 7; 671 672 auto FPI = buildFPI(*F1); 673 EXPECT_EQ(FPI, ExpectedInitial); 674 675 FunctionPropertiesUpdater FPU(FPI, *CB); 676 InlineFunctionInfo IFI; 677 auto IR = llvm::InlineFunction(*CB, IFI); 678 EXPECT_TRUE(IR.isSuccess()); 679 invalidate(*F1); 680 FPU.finish(FAM); 681 EXPECT_EQ(FPI, ExpectedFinal); 682 } 683 684 TEST_F(FunctionPropertiesAnalysisTest, InvokeSkipLP) { 685 LLVMContext C; 686 std::unique_ptr<Module> M = makeLLVMModule(C, 687 R"IR( 688 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 689 target triple = "x86_64-pc-linux-gnu" 690 691 define i64 @f1(i32 noundef %value) { 692 entry: 693 invoke fastcc void @f2() to label %cont unwind label %lpad 694 cont: 695 ret i64 1 696 lpad: 697 %lp = landingpad i32 cleanup 698 br label %ehcleanup 699 ehcleanup: 700 resume i32 0 701 } 702 define void @f2() { 703 invoke noundef void @f3() to label %exit unwind label %lpad 704 exit: 705 ret void 706 lpad: 707 %lp = landingpad i32 cleanup 708 resume i32 %lp 709 } 710 declare void @f3() 711 )IR"); 712 713 // The outcome of inlining will be that lpad becomes unreachable. The landing 714 // pad of the invoke inherited from f2 will land on a new bb which will branch 715 // to a bb containing the body of lpad. 716 Function *F1 = M->getFunction("f1"); 717 CallBase *CB = findCall(*F1); 718 EXPECT_NE(CB, nullptr); 719 720 FunctionPropertiesInfo ExpectedInitial; 721 ExpectedInitial.BasicBlockCount = 4; 722 ExpectedInitial.TotalInstructionCount = 5; 723 ExpectedInitial.BlocksReachedFromConditionalInstruction = 0; 724 ExpectedInitial.Uses = 1; 725 ExpectedInitial.DirectCallsToDefinedFunctions = 1; 726 727 FunctionPropertiesInfo ExpectedFinal = ExpectedInitial; 728 ExpectedFinal.BasicBlockCount = 6; 729 ExpectedFinal.DirectCallsToDefinedFunctions = 0; 730 ExpectedFinal.TotalInstructionCount = 8; 731 732 auto FPI = buildFPI(*F1); 733 EXPECT_EQ(FPI, ExpectedInitial); 734 735 FunctionPropertiesUpdater FPU(FPI, *CB); 736 InlineFunctionInfo IFI; 737 auto IR = llvm::InlineFunction(*CB, IFI); 738 EXPECT_TRUE(IR.isSuccess()); 739 invalidate(*F1); 740 FPU.finish(FAM); 741 EXPECT_EQ(FPI, ExpectedFinal); 742 } 743 } // end anonymous namespace 744