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), 329 F1->getBasicBlockList().size()); 330 EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount), 331 F1->getInstructionCount()); 332 } 333 334 TEST_F(FunctionPropertiesAnalysisTest, InvokeUnreachableHandler) { 335 LLVMContext C; 336 std::unique_ptr<Module> M = makeLLVMModule(C, 337 R"IR( 338 declare void @might_throw() 339 340 define internal i32 @callee() personality i32 (...)* @__gxx_personality_v0 { 341 entry: 342 invoke void @might_throw() 343 to label %cont unwind label %exc 344 345 cont: 346 ret i32 0 347 348 exc: 349 %exn = landingpad {i8*, i32} 350 cleanup 351 resume { i8*, i32 } %exn 352 } 353 354 define i32 @caller() personality i32 (...)* @__gxx_personality_v0 { 355 entry: 356 %X = invoke i32 @callee() 357 to label %cont unwind label %Handler 358 359 cont: 360 ret i32 %X 361 362 Handler: 363 %exn = landingpad {i8*, i32} 364 cleanup 365 ret i32 1 366 } 367 368 declare i32 @__gxx_personality_v0(...) 369 )IR"); 370 371 Function *F1 = M->getFunction("caller"); 372 CallBase* CB = findCall(*F1); 373 EXPECT_NE(CB, nullptr); 374 375 auto FPI = buildFPI(*F1); 376 FunctionPropertiesUpdater FPU(FPI, *CB); 377 InlineFunctionInfo IFI; 378 auto IR = llvm::InlineFunction(*CB, IFI); 379 EXPECT_TRUE(IR.isSuccess()); 380 invalidate(*F1); 381 FPU.finish(FAM); 382 EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), 383 F1->getBasicBlockList().size() - 1); 384 EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount), 385 F1->getInstructionCount() - 2); 386 EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM)); 387 } 388 389 TEST_F(FunctionPropertiesAnalysisTest, Rethrow) { 390 LLVMContext C; 391 std::unique_ptr<Module> M = makeLLVMModule(C, 392 R"IR( 393 declare void @might_throw() 394 395 define internal i32 @callee() personality i32 (...)* @__gxx_personality_v0 { 396 entry: 397 invoke void @might_throw() 398 to label %cont unwind label %exc 399 400 cont: 401 ret i32 0 402 403 exc: 404 %exn = landingpad {i8*, i32} 405 cleanup 406 resume { i8*, i32 } %exn 407 } 408 409 define i32 @caller() personality i32 (...)* @__gxx_personality_v0 { 410 entry: 411 %X = invoke i32 @callee() 412 to label %cont unwind label %Handler 413 414 cont: 415 ret i32 %X 416 417 Handler: 418 %exn = landingpad {i8*, i32} 419 cleanup 420 ret i32 1 421 } 422 423 declare i32 @__gxx_personality_v0(...) 424 )IR"); 425 426 Function *F1 = M->getFunction("caller"); 427 CallBase* CB = findCall(*F1); 428 EXPECT_NE(CB, nullptr); 429 430 auto FPI = buildFPI(*F1); 431 FunctionPropertiesUpdater FPU(FPI, *CB); 432 InlineFunctionInfo IFI; 433 auto IR = llvm::InlineFunction(*CB, IFI); 434 EXPECT_TRUE(IR.isSuccess()); 435 invalidate(*F1); 436 FPU.finish(FAM); 437 EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), 438 F1->getBasicBlockList().size() - 1); 439 EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount), 440 F1->getInstructionCount() - 2); 441 EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM)); 442 } 443 444 TEST_F(FunctionPropertiesAnalysisTest, LPadChanges) { 445 LLVMContext C; 446 std::unique_ptr<Module> M = makeLLVMModule(C, 447 R"IR( 448 declare void @external_func() 449 450 @exception_type1 = external global i8 451 @exception_type2 = external global i8 452 453 454 define internal void @inner() personality i8* null { 455 invoke void @external_func() 456 to label %cont unwind label %lpad 457 cont: 458 ret void 459 lpad: 460 %lp = landingpad i32 461 catch i8* @exception_type1 462 resume i32 %lp 463 } 464 465 define void @outer() personality i8* null { 466 invoke void @inner() 467 to label %cont unwind label %lpad 468 cont: 469 ret void 470 lpad: 471 %lp = landingpad i32 472 cleanup 473 catch i8* @exception_type2 474 resume i32 %lp 475 } 476 477 )IR"); 478 479 Function *F1 = M->getFunction("outer"); 480 CallBase* CB = findCall(*F1); 481 EXPECT_NE(CB, nullptr); 482 483 auto FPI = buildFPI(*F1); 484 FunctionPropertiesUpdater FPU(FPI, *CB); 485 InlineFunctionInfo IFI; 486 auto IR = llvm::InlineFunction(*CB, IFI); 487 EXPECT_TRUE(IR.isSuccess()); 488 invalidate(*F1); 489 FPU.finish(FAM); 490 EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), 491 F1->getBasicBlockList().size() - 1); 492 EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount), 493 F1->getInstructionCount() - 2); 494 EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM)); 495 } 496 497 TEST_F(FunctionPropertiesAnalysisTest, LPadChangesConditional) { 498 LLVMContext C; 499 std::unique_ptr<Module> M = makeLLVMModule(C, 500 R"IR( 501 declare void @external_func() 502 503 @exception_type1 = external global i8 504 @exception_type2 = external global i8 505 506 507 define internal void @inner() personality i8* null { 508 invoke void @external_func() 509 to label %cont unwind label %lpad 510 cont: 511 ret void 512 lpad: 513 %lp = landingpad i32 514 catch i8* @exception_type1 515 resume i32 %lp 516 } 517 518 define void @outer(i32 %a) personality i8* null { 519 entry: 520 %i = icmp slt i32 %a, 0 521 br i1 %i, label %if.then, label %cont 522 if.then: 523 invoke void @inner() 524 to label %cont unwind label %lpad 525 cont: 526 ret void 527 lpad: 528 %lp = landingpad i32 529 cleanup 530 catch i8* @exception_type2 531 resume i32 %lp 532 } 533 534 )IR"); 535 536 Function *F1 = M->getFunction("outer"); 537 CallBase* CB = findCall(*F1); 538 EXPECT_NE(CB, nullptr); 539 540 auto FPI = buildFPI(*F1); 541 FunctionPropertiesUpdater FPU(FPI, *CB); 542 InlineFunctionInfo IFI; 543 auto IR = llvm::InlineFunction(*CB, IFI); 544 EXPECT_TRUE(IR.isSuccess()); 545 invalidate(*F1); 546 FPU.finish(FAM); 547 EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), 548 F1->getBasicBlockList().size() - 1); 549 EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount), 550 F1->getInstructionCount() - 2); 551 EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM)); 552 } 553 554 TEST_F(FunctionPropertiesAnalysisTest, InlineSameLoopBB) { 555 LLVMContext C; 556 std::unique_ptr<Module> M = makeLLVMModule(C, 557 R"IR( 558 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 559 target triple = "x86_64-pc-linux-gnu" 560 561 declare i32 @a() 562 declare i32 @b() 563 564 define i32 @f1(i32 %a) { 565 entry: 566 br label %loop 567 loop: 568 %i = call i32 @f2(i32 %a) 569 %c = icmp slt i32 %i, %a 570 br i1 %c, label %loop, label %end 571 end: 572 %r = phi i32 [%i, %loop], [%a, %entry] 573 ret i32 %r 574 } 575 576 define i32 @f2(i32 %a) { 577 %cnd = icmp slt i32 %a, 0 578 br i1 %cnd, label %then, label %else 579 then: 580 %r1 = call i32 @a() 581 br label %end 582 else: 583 %r2 = call i32 @b() 584 br label %end 585 end: 586 %r = phi i32 [%r1, %then], [%r2, %else] 587 ret i32 %r 588 } 589 )IR"); 590 591 Function *F1 = M->getFunction("f1"); 592 CallBase *CB = findCall(*F1); 593 EXPECT_NE(CB, nullptr); 594 595 FunctionPropertiesInfo ExpectedInitial; 596 ExpectedInitial.BasicBlockCount = 3; 597 ExpectedInitial.TotalInstructionCount = 6; 598 ExpectedInitial.BlocksReachedFromConditionalInstruction = 2; 599 ExpectedInitial.Uses = 1; 600 ExpectedInitial.DirectCallsToDefinedFunctions = 1; 601 ExpectedInitial.MaxLoopDepth = 1; 602 ExpectedInitial.TopLevelLoopCount = 1; 603 604 FunctionPropertiesInfo ExpectedFinal = ExpectedInitial; 605 ExpectedFinal.BasicBlockCount = 6; 606 ExpectedFinal.DirectCallsToDefinedFunctions = 0; 607 ExpectedFinal.BlocksReachedFromConditionalInstruction = 4; 608 ExpectedFinal.TotalInstructionCount = 12; 609 610 auto FPI = buildFPI(*F1); 611 EXPECT_EQ(FPI, ExpectedInitial); 612 613 FunctionPropertiesUpdater FPU(FPI, *CB); 614 InlineFunctionInfo IFI; 615 auto IR = llvm::InlineFunction(*CB, IFI); 616 EXPECT_TRUE(IR.isSuccess()); 617 invalidate(*F1); 618 FPU.finish(FAM); 619 EXPECT_EQ(FPI, ExpectedFinal); 620 } 621 622 TEST_F(FunctionPropertiesAnalysisTest, Unreachable) { 623 LLVMContext C; 624 std::unique_ptr<Module> M = makeLLVMModule(C, 625 R"IR( 626 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 627 target triple = "x86_64-pc-linux-gnu" 628 629 define i64 @f1(i32 noundef %value) { 630 entry: 631 br i1 true, label %cond.true, label %cond.false 632 633 cond.true: ; preds = %entry 634 %conv2 = sext i32 %value to i64 635 br label %cond.end 636 637 cond.false: ; preds = %entry 638 %call3 = call noundef i64 @f2() 639 br label %cond.end 640 641 cond.end: ; preds = %cond.false, %cond.true 642 %cond = phi i64 [ %conv2, %cond.true ], [ %call3, %cond.false ] 643 ret i64 %cond 644 } 645 646 define i64 @f2() { 647 entry: 648 tail call void @llvm.trap() 649 unreachable 650 } 651 652 declare void @llvm.trap() 653 )IR"); 654 655 Function *F1 = M->getFunction("f1"); 656 CallBase *CB = findCall(*F1); 657 EXPECT_NE(CB, nullptr); 658 659 FunctionPropertiesInfo ExpectedInitial; 660 ExpectedInitial.BasicBlockCount = 4; 661 ExpectedInitial.TotalInstructionCount = 7; 662 ExpectedInitial.BlocksReachedFromConditionalInstruction = 2; 663 ExpectedInitial.Uses = 1; 664 ExpectedInitial.DirectCallsToDefinedFunctions = 1; 665 666 FunctionPropertiesInfo ExpectedFinal = ExpectedInitial; 667 ExpectedFinal.BasicBlockCount = 4; 668 ExpectedFinal.DirectCallsToDefinedFunctions = 0; 669 ExpectedFinal.TotalInstructionCount = 7; 670 671 auto FPI = buildFPI(*F1); 672 EXPECT_EQ(FPI, ExpectedInitial); 673 674 FunctionPropertiesUpdater FPU(FPI, *CB); 675 InlineFunctionInfo IFI; 676 auto IR = llvm::InlineFunction(*CB, IFI); 677 EXPECT_TRUE(IR.isSuccess()); 678 invalidate(*F1); 679 FPU.finish(FAM); 680 EXPECT_EQ(FPI, ExpectedFinal); 681 } 682 683 } // end anonymous namespace 684