1217 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Analysis/FunctionPropertiesAnalysis.h"10#include "llvm/Analysis/AliasAnalysis.h"11#include "llvm/Analysis/IR2Vec.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/Compiler.h"22#include "llvm/Support/SourceMgr.h"23#include "llvm/Transforms/Utils/Cloning.h"24#include "gmock/gmock.h"25#include "gtest/gtest.h"26#include <cstring>27 28using namespace llvm;29using namespace testing;30 31namespace llvm {32LLVM_ABI extern cl::opt<bool> EnableDetailedFunctionProperties;33LLVM_ABI extern cl::opt<bool> BigBasicBlockInstructionThreshold;34LLVM_ABI extern cl::opt<bool> MediumBasicBlockInstrutionThreshold;35LLVM_ABI extern cl::opt<float> ir2vec::OpcWeight;36LLVM_ABI extern cl::opt<float> ir2vec::TypeWeight;37LLVM_ABI extern cl::opt<float> ir2vec::ArgWeight;38} // namespace llvm39 40namespace {41 42class FunctionPropertiesAnalysisTest : public testing::Test {43public:44 FunctionPropertiesAnalysisTest() {45 auto VocabVector = ir2vec::Vocabulary::createDummyVocabForTest(1);46 MAM.registerPass([VocabVector = std::move(VocabVector)]() mutable {47 return IR2VecVocabAnalysis(std::move(VocabVector));48 });49 IR2VecVocab = std::make_unique<ir2vec::Vocabulary>(50 ir2vec::Vocabulary::createDummyVocabForTest(1));51 MAM.registerPass([&] { return PassInstrumentationAnalysis(); });52 FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });53 FAM.registerPass([&] { return DominatorTreeAnalysis(); });54 FAM.registerPass([&] { return LoopAnalysis(); });55 FAM.registerPass([&] { return PassInstrumentationAnalysis(); });56 57 ir2vec::OpcWeight = 1.0;58 ir2vec::TypeWeight = 1.0;59 ir2vec::ArgWeight = 1.0;60 }61 62private:63 float OriginalOpcWeight = ir2vec::OpcWeight;64 float OriginalTypeWeight = ir2vec::TypeWeight;65 float OriginalArgWeight = ir2vec::ArgWeight;66 67protected:68 std::unique_ptr<DominatorTree> DT;69 std::unique_ptr<LoopInfo> LI;70 FunctionAnalysisManager FAM;71 ModuleAnalysisManager MAM;72 std::unique_ptr<ir2vec::Vocabulary> IR2VecVocab;73 74 void TearDown() override {75 // Restore original IR2Vec weights76 ir2vec::OpcWeight = OriginalOpcWeight;77 ir2vec::TypeWeight = OriginalTypeWeight;78 ir2vec::ArgWeight = OriginalArgWeight;79 }80 81 FunctionPropertiesInfo buildFPI(Function &F) {82 // FunctionPropertiesInfo assumes IR2VecVocabAnalysis has been run to83 // use IR2Vec.84 auto &VocabResult = MAM.getResult<IR2VecVocabAnalysis>(*F.getParent());85 (void)VocabResult;86 return FunctionPropertiesInfo::getFunctionPropertiesInfo(F, FAM);87 }88 89 void invalidate(Function &F) {90 PreservedAnalyses PA = PreservedAnalyses::none();91 FAM.invalidate(F, PA);92 }93 94 std::unique_ptr<Module> makeLLVMModule(LLVMContext &C, const char *IR) {95 SMDiagnostic Err;96 std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);97 if (!Mod)98 Err.print("MLAnalysisTests", errs());99 return Mod;100 }101 102 CallBase *findCall(Function &F, const char *Name = nullptr) {103 for (auto &BB : F)104 for (auto &I : BB)105 if (auto *CB = dyn_cast<CallBase>(&I))106 if (!Name || CB->getName() == Name)107 return CB;108 return nullptr;109 }110 111 std::unique_ptr<ir2vec::Embedder> createEmbedder(const Function &F) {112 auto Emb = ir2vec::Embedder::create(IR2VecKind::Symbolic, F, *IR2VecVocab);113 EXPECT_TRUE(static_cast<bool>(Emb));114 return Emb;115 }116};117 118TEST_F(FunctionPropertiesAnalysisTest, BasicTest) {119 LLVMContext C;120 std::unique_ptr<Module> M = makeLLVMModule(C,121 R"IR(122target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"123target triple = "x86_64-pc-linux-gnu"124declare i32 @f1(i32)125declare i32 @f2(i32)126define i32 @branches(i32) {127 %cond = icmp slt i32 %0, 3128 br i1 %cond, label %then, label %else129then:130 %ret.1 = call i32 @f1(i32 %0)131 br label %last.block132else:133 %ret.2 = call i32 @f2(i32 %0)134 br label %last.block135last.block:136 %ret = phi i32 [%ret.1, %then], [%ret.2, %else]137 ret i32 %ret138}139define internal i32 @top() {140 %1 = call i32 @branches(i32 2)141 %2 = call i32 @f1(i32 %1)142 ret i32 %2143}144)IR");145 146 Function *BranchesFunction = M->getFunction("branches");147 FunctionPropertiesInfo BranchesFeatures = buildFPI(*BranchesFunction);148 EXPECT_EQ(BranchesFeatures.BasicBlockCount, 4);149 EXPECT_EQ(BranchesFeatures.BlocksReachedFromConditionalInstruction, 2);150 // 2 Users: top is one. The other is added because @branches is not internal,151 // so it may have external callers.152 EXPECT_EQ(BranchesFeatures.Uses, 2);153 EXPECT_EQ(BranchesFeatures.DirectCallsToDefinedFunctions, 0);154 EXPECT_EQ(BranchesFeatures.LoadInstCount, 0);155 EXPECT_EQ(BranchesFeatures.StoreInstCount, 0);156 EXPECT_EQ(BranchesFeatures.MaxLoopDepth, 0);157 EXPECT_EQ(BranchesFeatures.TopLevelLoopCount, 0);158 EXPECT_TRUE(BranchesFeatures.getFunctionEmbedding().approximatelyEquals(159 createEmbedder(*BranchesFunction)->getFunctionVector()));160 161 Function *TopFunction = M->getFunction("top");162 FunctionPropertiesInfo TopFeatures = buildFPI(*TopFunction);163 EXPECT_EQ(TopFeatures.BasicBlockCount, 1);164 EXPECT_EQ(TopFeatures.BlocksReachedFromConditionalInstruction, 0);165 EXPECT_EQ(TopFeatures.Uses, 0);166 EXPECT_EQ(TopFeatures.DirectCallsToDefinedFunctions, 1);167 EXPECT_TRUE(TopFeatures.getFunctionEmbedding().approximatelyEquals(168 createEmbedder(*TopFunction)->getFunctionVector()));169 EXPECT_EQ(BranchesFeatures.LoadInstCount, 0);170 EXPECT_EQ(BranchesFeatures.StoreInstCount, 0);171 EXPECT_EQ(BranchesFeatures.MaxLoopDepth, 0);172 EXPECT_EQ(BranchesFeatures.TopLevelLoopCount, 0);173 174 EnableDetailedFunctionProperties.setValue(true);175 FunctionPropertiesInfo DetailedBranchesFeatures = buildFPI(*BranchesFunction);176 EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithSingleSuccessor, 2);177 EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithTwoSuccessors, 1);178 EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithMoreThanTwoSuccessors, 0);179 EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithSinglePredecessor, 2);180 EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithTwoPredecessors, 1);181 EXPECT_EQ(DetailedBranchesFeatures.BasicBlocksWithMoreThanTwoPredecessors, 0);182 EXPECT_EQ(DetailedBranchesFeatures.BigBasicBlocks, 0);183 EXPECT_EQ(DetailedBranchesFeatures.MediumBasicBlocks, 0);184 EXPECT_EQ(DetailedBranchesFeatures.SmallBasicBlocks, 4);185 EXPECT_EQ(DetailedBranchesFeatures.CastInstructionCount, 0);186 EXPECT_EQ(DetailedBranchesFeatures.FloatingPointInstructionCount, 0);187 EXPECT_EQ(DetailedBranchesFeatures.IntegerInstructionCount, 4);188 EXPECT_EQ(DetailedBranchesFeatures.ConstantIntOperandCount, 1);189 EXPECT_EQ(DetailedBranchesFeatures.ConstantFPOperandCount, 0);190 EXPECT_EQ(DetailedBranchesFeatures.ConstantOperandCount, 0);191 EXPECT_EQ(DetailedBranchesFeatures.InstructionOperandCount, 4);192 EXPECT_EQ(DetailedBranchesFeatures.BasicBlockOperandCount, 4);193 EXPECT_EQ(DetailedBranchesFeatures.GlobalValueOperandCount, 2);194 EXPECT_EQ(DetailedBranchesFeatures.InlineAsmOperandCount, 0);195 EXPECT_EQ(DetailedBranchesFeatures.ArgumentOperandCount, 3);196 EXPECT_EQ(DetailedBranchesFeatures.UnknownOperandCount, 0);197 EXPECT_EQ(DetailedBranchesFeatures.CriticalEdgeCount, 0);198 EXPECT_EQ(DetailedBranchesFeatures.ControlFlowEdgeCount, 4);199 EXPECT_EQ(DetailedBranchesFeatures.UnconditionalBranchCount, 2);200 EXPECT_EQ(DetailedBranchesFeatures.IntrinsicCount, 0);201 EXPECT_EQ(DetailedBranchesFeatures.DirectCallCount, 2);202 EXPECT_EQ(DetailedBranchesFeatures.IndirectCallCount, 0);203 EXPECT_EQ(DetailedBranchesFeatures.CallReturnsIntegerCount, 2);204 EXPECT_EQ(DetailedBranchesFeatures.CallReturnsFloatCount, 0);205 EXPECT_EQ(DetailedBranchesFeatures.CallReturnsPointerCount, 0);206 EXPECT_EQ(DetailedBranchesFeatures.CallWithManyArgumentsCount, 0);207 EXPECT_EQ(DetailedBranchesFeatures.CallWithPointerArgumentCount, 0);208 EXPECT_TRUE(209 DetailedBranchesFeatures.getFunctionEmbedding().approximatelyEquals(210 createEmbedder(*BranchesFunction)->getFunctionVector()));211 EnableDetailedFunctionProperties.setValue(false);212}213 214TEST_F(FunctionPropertiesAnalysisTest, DifferentPredecessorSuccessorCounts) {215 LLVMContext C;216 std::unique_ptr<Module> M = makeLLVMModule(C,217 R"IR(218define i64 @f1() {219 br i1 0, label %br1, label %finally220br1:221 ret i64 0222finally:223 ret i64 3224}225)IR");226 227 Function *F1 = M->getFunction("f1");228 EnableDetailedFunctionProperties.setValue(true);229 FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);230 EXPECT_EQ(DetailedF1Properties.BasicBlocksWithSingleSuccessor, 0);231 EXPECT_EQ(DetailedF1Properties.BasicBlocksWithTwoSuccessors, 1);232 EXPECT_EQ(DetailedF1Properties.BasicBlocksWithMoreThanTwoSuccessors, 0);233 EXPECT_EQ(DetailedF1Properties.BasicBlocksWithSinglePredecessor, 2);234 EXPECT_EQ(DetailedF1Properties.BasicBlocksWithTwoPredecessors, 0);235 EXPECT_EQ(DetailedF1Properties.BasicBlocksWithMoreThanTwoPredecessors, 0);236 EXPECT_EQ(DetailedF1Properties.BigBasicBlocks, 0);237 EXPECT_EQ(DetailedF1Properties.MediumBasicBlocks, 0);238 EXPECT_EQ(DetailedF1Properties.SmallBasicBlocks, 3);239 EXPECT_EQ(DetailedF1Properties.CastInstructionCount, 0);240 EXPECT_EQ(DetailedF1Properties.FloatingPointInstructionCount, 0);241 EXPECT_EQ(DetailedF1Properties.IntegerInstructionCount, 0);242 EXPECT_EQ(DetailedF1Properties.ConstantIntOperandCount, 3);243 EXPECT_EQ(DetailedF1Properties.ConstantFPOperandCount, 0);244 EXPECT_EQ(DetailedF1Properties.ConstantOperandCount, 0);245 EXPECT_EQ(DetailedF1Properties.InstructionOperandCount, 0);246 EXPECT_EQ(DetailedF1Properties.BasicBlockOperandCount, 2);247 EXPECT_EQ(DetailedF1Properties.GlobalValueOperandCount, 0);248 EXPECT_EQ(DetailedF1Properties.InlineAsmOperandCount, 0);249 EXPECT_EQ(DetailedF1Properties.ArgumentOperandCount, 0);250 EXPECT_EQ(DetailedF1Properties.UnknownOperandCount, 0);251 EXPECT_EQ(DetailedF1Properties.CriticalEdgeCount, 0);252 EXPECT_EQ(DetailedF1Properties.ControlFlowEdgeCount, 2);253 EXPECT_EQ(DetailedF1Properties.UnconditionalBranchCount, 0);254 EXPECT_EQ(DetailedF1Properties.IntrinsicCount, 0);255 EXPECT_EQ(DetailedF1Properties.DirectCallCount, 0);256 EXPECT_EQ(DetailedF1Properties.IndirectCallCount, 0);257 EXPECT_EQ(DetailedF1Properties.CallReturnsIntegerCount, 0);258 EXPECT_EQ(DetailedF1Properties.CallReturnsFloatCount, 0);259 EXPECT_EQ(DetailedF1Properties.CallReturnsPointerCount, 0);260 EXPECT_EQ(DetailedF1Properties.CallWithManyArgumentsCount, 0);261 EXPECT_EQ(DetailedF1Properties.CallWithPointerArgumentCount, 0);262 EXPECT_TRUE(DetailedF1Properties.getFunctionEmbedding().approximatelyEquals(263 createEmbedder(*F1)->getFunctionVector()));264 EnableDetailedFunctionProperties.setValue(false);265}266 267TEST_F(FunctionPropertiesAnalysisTest, InlineSameBBSimple) {268 LLVMContext C;269 std::unique_ptr<Module> M = makeLLVMModule(C,270 R"IR(271target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"272target triple = "x86_64-pc-linux-gnu"273define i32 @f1(i32 %a) {274 %b = call i32 @f2(i32 %a)275 %c = add i32 %b, 2276 ret i32 %c277}278 279define i32 @f2(i32 %a) {280 %b = add i32 %a, 1281 ret i32 %b282}283)IR");284 285 Function *F1 = M->getFunction("f1");286 CallBase *CB = findCall(*F1, "b");287 EXPECT_NE(CB, nullptr);288 289 FunctionPropertiesInfo ExpectedInitial;290 ExpectedInitial.BasicBlockCount = 1;291 ExpectedInitial.TotalInstructionCount = 3;292 ExpectedInitial.Uses = 1;293 ExpectedInitial.DirectCallsToDefinedFunctions = 1;294 ExpectedInitial.setFunctionEmbeddingForTest(295 createEmbedder(*F1)->getFunctionVector());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 ExpectedFinal.setFunctionEmbeddingForTest(309 createEmbedder(*F1)->getFunctionVector());310 311 EXPECT_TRUE(FPU.finishAndTest(FAM));312 EXPECT_EQ(FPI, ExpectedFinal);313}314 315TEST_F(FunctionPropertiesAnalysisTest, InlineSameBBLargerCFG) {316 LLVMContext C;317 std::unique_ptr<Module> M = makeLLVMModule(C,318 R"IR(319target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"320target triple = "x86_64-pc-linux-gnu"321define i32 @f1(i32 %a) {322entry:323 %i = icmp slt i32 %a, 0324 br i1 %i, label %if.then, label %if.else325if.then:326 %b = call i32 @f2(i32 %a)327 %c1 = add i32 %b, 2328 br label %end329if.else:330 %c2 = add i32 %a, 1331 br label %end332end:333 %ret = phi i32 [%c1, %if.then],[%c2, %if.else]334 ret i32 %ret335}336 337define i32 @f2(i32 %a) {338 %b = add i32 %a, 1339 ret i32 %b340}341)IR");342 343 Function *F1 = M->getFunction("f1");344 CallBase *CB = findCall(*F1, "b");345 EXPECT_NE(CB, nullptr);346 347 FunctionPropertiesInfo ExpectedInitial;348 ExpectedInitial.BasicBlockCount = 4;349 ExpectedInitial.BlocksReachedFromConditionalInstruction = 2;350 ExpectedInitial.TotalInstructionCount = 9;351 ExpectedInitial.Uses = 1;352 ExpectedInitial.DirectCallsToDefinedFunctions = 1;353 ExpectedInitial.setFunctionEmbeddingForTest(354 createEmbedder(*F1)->getFunctionVector());355 356 FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;357 ExpectedFinal.DirectCallsToDefinedFunctions = 0;358 359 auto FPI = buildFPI(*F1);360 EXPECT_EQ(FPI, ExpectedInitial);361 362 FunctionPropertiesUpdater FPU(FPI, *CB);363 InlineFunctionInfo IFI;364 auto IR = llvm::InlineFunction(*CB, IFI);365 EXPECT_TRUE(IR.isSuccess());366 invalidate(*F1);367 EXPECT_TRUE(FPU.finishAndTest(FAM));368 369 ExpectedFinal.setFunctionEmbeddingForTest(370 createEmbedder(*F1)->getFunctionVector());371 EXPECT_EQ(FPI, ExpectedFinal);372}373 374TEST_F(FunctionPropertiesAnalysisTest, InlineSameBBLoops) {375 LLVMContext C;376 std::unique_ptr<Module> M = makeLLVMModule(C,377 R"IR(378target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"379target triple = "x86_64-pc-linux-gnu"380define i32 @f1(i32 %a) {381entry:382 %i = icmp slt i32 %a, 0383 br i1 %i, label %if.then, label %if.else384if.then:385 %b = call i32 @f2(i32 %a)386 %c1 = add i32 %b, 2387 br label %end388if.else:389 %c2 = add i32 %a, 1390 br label %end391end:392 %ret = phi i32 [%c1, %if.then],[%c2, %if.else]393 ret i32 %ret394}395 396define i32 @f2(i32 %a) {397entry:398 br label %loop399loop:400 %indvar = phi i32 [%indvar.next, %loop], [0, %entry]401 %b = add i32 %a, %indvar402 %indvar.next = add i32 %indvar, 1403 %cond = icmp slt i32 %indvar.next, %a404 br i1 %cond, label %loop, label %exit405exit:406 ret i32 %b407}408)IR");409 410 Function *F1 = M->getFunction("f1");411 CallBase *CB = findCall(*F1, "b");412 EXPECT_NE(CB, nullptr);413 414 FunctionPropertiesInfo ExpectedInitial;415 ExpectedInitial.BasicBlockCount = 4;416 ExpectedInitial.BlocksReachedFromConditionalInstruction = 2;417 ExpectedInitial.TotalInstructionCount = 9;418 ExpectedInitial.Uses = 1;419 ExpectedInitial.DirectCallsToDefinedFunctions = 1;420 ExpectedInitial.setFunctionEmbeddingForTest(421 createEmbedder(*F1)->getFunctionVector());422 423 FunctionPropertiesInfo ExpectedFinal;424 ExpectedFinal.BasicBlockCount = 6;425 ExpectedFinal.BlocksReachedFromConditionalInstruction = 4;426 ExpectedFinal.Uses = 1;427 ExpectedFinal.MaxLoopDepth = 1;428 ExpectedFinal.TopLevelLoopCount = 1;429 ExpectedFinal.TotalInstructionCount = 14;430 431 auto FPI = buildFPI(*F1);432 EXPECT_EQ(FPI, ExpectedInitial);433 FunctionPropertiesUpdater FPU(FPI, *CB);434 InlineFunctionInfo IFI;435 436 auto IR = llvm::InlineFunction(*CB, IFI);437 EXPECT_TRUE(IR.isSuccess());438 invalidate(*F1);439 EXPECT_TRUE(FPU.finishAndTest(FAM));440 441 ExpectedFinal.setFunctionEmbeddingForTest(442 createEmbedder(*F1)->getFunctionVector());443 EXPECT_EQ(FPI, ExpectedFinal);444}445 446TEST_F(FunctionPropertiesAnalysisTest, InvokeSimple) {447 LLVMContext C;448 std::unique_ptr<Module> M = makeLLVMModule(C,449 R"IR(450target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"451target triple = "x86_64-pc-linux-gnu"452declare void @might_throw()453 454define internal void @callee() {455entry:456 call void @might_throw()457 ret void458}459 460define i32 @caller() personality ptr @__gxx_personality_v0 {461entry:462 invoke void @callee()463 to label %cont unwind label %exc464 465cont:466 ret i32 0467 468exc:469 %exn = landingpad {ptr, i32}470 cleanup471 ret i32 1472}473 474declare i32 @__gxx_personality_v0(...)475)IR");476 477 Function *F1 = M->getFunction("caller");478 CallBase *CB = findCall(*F1);479 EXPECT_NE(CB, nullptr);480 481 auto FPI = buildFPI(*F1);482 FunctionPropertiesUpdater FPU(FPI, *CB);483 InlineFunctionInfo IFI;484 auto IR = llvm::InlineFunction(*CB, IFI);485 EXPECT_TRUE(IR.isSuccess());486 invalidate(*F1);487 EXPECT_TRUE(FPU.finishAndTest(FAM));488 EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size());489 EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),490 F1->getInstructionCount());491 EXPECT_TRUE(FPI.getFunctionEmbedding().approximatelyEquals(492 createEmbedder(*F1)->getFunctionVector()));493}494 495TEST_F(FunctionPropertiesAnalysisTest, InvokeUnreachableHandler) {496 LLVMContext C;497 std::unique_ptr<Module> M = makeLLVMModule(C,498 R"IR(499declare void @might_throw()500 501define internal i32 @callee() personality ptr @__gxx_personality_v0 {502entry:503 invoke void @might_throw()504 to label %cont unwind label %exc505 506cont:507 ret i32 0508 509exc:510 %exn = landingpad {ptr, i32}511 cleanup512 resume { ptr, i32 } %exn513}514 515define i32 @caller() personality ptr @__gxx_personality_v0 {516entry:517 %X = invoke i32 @callee()518 to label %cont unwind label %Handler519 520cont:521 ret i32 %X522 523Handler:524 %exn = landingpad {ptr, i32}525 cleanup526 ret i32 1527}528 529declare i32 @__gxx_personality_v0(...)530)IR");531 532 Function *F1 = M->getFunction("caller");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 EXPECT_TRUE(FPU.finishAndTest(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_TRUE(FPI.getFunctionEmbedding().approximatelyEquals(547 createEmbedder(*F1)->getFunctionVector()));548 EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));549}550 551TEST_F(FunctionPropertiesAnalysisTest, Rethrow) {552 LLVMContext C;553 std::unique_ptr<Module> M = makeLLVMModule(C,554 R"IR(555declare void @might_throw()556 557define internal i32 @callee() personality ptr @__gxx_personality_v0 {558entry:559 invoke void @might_throw()560 to label %cont unwind label %exc561 562cont:563 ret i32 0564 565exc:566 %exn = landingpad {ptr, i32}567 cleanup568 resume { ptr, i32 } %exn569}570 571define i32 @caller() personality ptr @__gxx_personality_v0 {572entry:573 %X = invoke i32 @callee()574 to label %cont unwind label %Handler575 576cont:577 ret i32 %X578 579Handler:580 %exn = landingpad {ptr, i32}581 cleanup582 ret i32 1583}584 585declare i32 @__gxx_personality_v0(...)586)IR");587 588 Function *F1 = M->getFunction("caller");589 CallBase *CB = findCall(*F1);590 EXPECT_NE(CB, nullptr);591 592 auto FPI = buildFPI(*F1);593 FunctionPropertiesUpdater FPU(FPI, *CB);594 InlineFunctionInfo IFI;595 auto IR = llvm::InlineFunction(*CB, IFI);596 EXPECT_TRUE(IR.isSuccess());597 invalidate(*F1);598 EXPECT_TRUE(FPU.finishAndTest(FAM));599 EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size() - 1);600 EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),601 F1->getInstructionCount() - 2);602 EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));603}604 605TEST_F(FunctionPropertiesAnalysisTest, LPadChanges) {606 LLVMContext C;607 std::unique_ptr<Module> M = makeLLVMModule(C,608 R"IR(609declare void @external_func()610 611@exception_type1 = external global i8612@exception_type2 = external global i8613 614 615define internal void @inner() personality ptr null {616 invoke void @external_func()617 to label %cont unwind label %lpad618cont:619 ret void620lpad:621 %lp = landingpad i32622 catch ptr @exception_type1623 resume i32 %lp624}625 626define void @outer() personality ptr null {627 invoke void @inner()628 to label %cont unwind label %lpad629cont:630 ret void631lpad:632 %lp = landingpad i32633 cleanup634 catch ptr @exception_type2635 resume i32 %lp636}637 638)IR");639 640 Function *F1 = M->getFunction("outer");641 CallBase *CB = findCall(*F1);642 EXPECT_NE(CB, nullptr);643 644 auto FPI = buildFPI(*F1);645 FunctionPropertiesUpdater FPU(FPI, *CB);646 InlineFunctionInfo IFI;647 auto IR = llvm::InlineFunction(*CB, IFI);648 EXPECT_TRUE(IR.isSuccess());649 invalidate(*F1);650 EXPECT_TRUE(FPU.finishAndTest(FAM));651 EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size() - 1);652 EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),653 F1->getInstructionCount() - 2);654 EXPECT_TRUE(FPI.getFunctionEmbedding().approximatelyEquals(655 createEmbedder(*F1)->getFunctionVector()));656 EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));657}658 659TEST_F(FunctionPropertiesAnalysisTest, LPadChangesConditional) {660 LLVMContext C;661 std::unique_ptr<Module> M = makeLLVMModule(C,662 R"IR(663declare void @external_func()664 665@exception_type1 = external global i8666@exception_type2 = external global i8667 668 669define internal void @inner() personality ptr null {670 invoke void @external_func()671 to label %cont unwind label %lpad672cont:673 ret void674lpad:675 %lp = landingpad i32676 catch ptr @exception_type1677 resume i32 %lp678}679 680define void @outer(i32 %a) personality ptr null {681entry:682 %i = icmp slt i32 %a, 0683 br i1 %i, label %if.then, label %cont684if.then:685 invoke void @inner()686 to label %cont unwind label %lpad687cont:688 ret void689lpad:690 %lp = landingpad i32691 cleanup692 catch ptr @exception_type2693 resume i32 %lp694}695 696)IR");697 698 Function *F1 = M->getFunction("outer");699 CallBase *CB = findCall(*F1);700 EXPECT_NE(CB, nullptr);701 702 auto FPI = buildFPI(*F1);703 FunctionPropertiesUpdater FPU(FPI, *CB);704 InlineFunctionInfo IFI;705 auto IR = llvm::InlineFunction(*CB, IFI);706 EXPECT_TRUE(IR.isSuccess());707 invalidate(*F1);708 EXPECT_TRUE(FPU.finishAndTest(FAM));709 EXPECT_EQ(static_cast<size_t>(FPI.BasicBlockCount), F1->size() - 1);710 EXPECT_EQ(static_cast<size_t>(FPI.TotalInstructionCount),711 F1->getInstructionCount() - 2);712 EXPECT_TRUE(FPI.getFunctionEmbedding().approximatelyEquals(713 createEmbedder(*F1)->getFunctionVector()));714 EXPECT_EQ(FPI, FunctionPropertiesInfo::getFunctionPropertiesInfo(*F1, FAM));715}716 717TEST_F(FunctionPropertiesAnalysisTest, InlineSameLoopBB) {718 LLVMContext C;719 std::unique_ptr<Module> M = makeLLVMModule(C,720 R"IR(721target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"722target triple = "x86_64-pc-linux-gnu"723 724declare i32 @a()725declare i32 @b()726 727define i32 @f1(i32 %a) {728entry:729 br label %loop730loop:731 %i = call i32 @f2(i32 %a)732 %c = icmp slt i32 %i, %a733 br i1 %c, label %loop, label %end734end:735 %r = phi i32 [%i, %loop], [%a, %entry]736 ret i32 %r737}738 739define i32 @f2(i32 %a) {740 %cnd = icmp slt i32 %a, 0741 br i1 %cnd, label %then, label %else742then:743 %r1 = call i32 @a()744 br label %end745else:746 %r2 = call i32 @b()747 br label %end748end:749 %r = phi i32 [%r1, %then], [%r2, %else]750 ret i32 %r751}752)IR");753 754 Function *F1 = M->getFunction("f1");755 CallBase *CB = findCall(*F1);756 EXPECT_NE(CB, nullptr);757 758 FunctionPropertiesInfo ExpectedInitial;759 ExpectedInitial.BasicBlockCount = 3;760 ExpectedInitial.TotalInstructionCount = 6;761 ExpectedInitial.BlocksReachedFromConditionalInstruction = 2;762 ExpectedInitial.Uses = 1;763 ExpectedInitial.DirectCallsToDefinedFunctions = 1;764 ExpectedInitial.MaxLoopDepth = 1;765 ExpectedInitial.TopLevelLoopCount = 1;766 ExpectedInitial.setFunctionEmbeddingForTest(767 createEmbedder(*F1)->getFunctionVector());768 769 FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;770 ExpectedFinal.BasicBlockCount = 6;771 ExpectedFinal.DirectCallsToDefinedFunctions = 0;772 ExpectedFinal.BlocksReachedFromConditionalInstruction = 4;773 ExpectedFinal.TotalInstructionCount = 12;774 775 auto FPI = buildFPI(*F1);776 EXPECT_EQ(FPI, ExpectedInitial);777 778 FunctionPropertiesUpdater FPU(FPI, *CB);779 InlineFunctionInfo IFI;780 auto IR = llvm::InlineFunction(*CB, IFI);781 EXPECT_TRUE(IR.isSuccess());782 invalidate(*F1);783 EXPECT_TRUE(FPU.finishAndTest(FAM));784 785 ExpectedFinal.setFunctionEmbeddingForTest(786 createEmbedder(*F1)->getFunctionVector());787 EXPECT_EQ(FPI, ExpectedFinal);788}789 790TEST_F(FunctionPropertiesAnalysisTest, Unreachable) {791 LLVMContext C;792 std::unique_ptr<Module> M = makeLLVMModule(C,793 R"IR(794target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"795target triple = "x86_64-pc-linux-gnu"796 797define i64 @f1(i32 noundef %value) {798entry:799 br i1 true, label %cond.true, label %cond.false800 801cond.true: ; preds = %entry802 %conv2 = sext i32 %value to i64803 br label %cond.end804 805cond.false: ; preds = %entry806 %call3 = call noundef i64 @f2()807 br label %extra808 809extra:810 br label %extra2811 812extra2:813 br label %cond.end814 815cond.end: ; preds = %extra2, %cond.true816 %cond = phi i64 [ %conv2, %cond.true ], [ %call3, %extra ]817 ret i64 %cond818}819 820define i64 @f2() {821entry:822 tail call void @llvm.trap()823 unreachable824}825 826declare void @llvm.trap()827)IR");828 829 Function *F1 = M->getFunction("f1");830 CallBase *CB = findCall(*F1);831 EXPECT_NE(CB, nullptr);832 833 FunctionPropertiesInfo ExpectedInitial;834 ExpectedInitial.BasicBlockCount = 6;835 ExpectedInitial.TotalInstructionCount = 9;836 ExpectedInitial.BlocksReachedFromConditionalInstruction = 2;837 ExpectedInitial.Uses = 1;838 ExpectedInitial.DirectCallsToDefinedFunctions = 1;839 ExpectedInitial.setFunctionEmbeddingForTest(840 createEmbedder(*F1)->getFunctionVector());841 842 FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;843 ExpectedFinal.BasicBlockCount = 4;844 ExpectedFinal.DirectCallsToDefinedFunctions = 0;845 ExpectedFinal.TotalInstructionCount = 7;846 847 auto FPI = buildFPI(*F1);848 EXPECT_EQ(FPI, ExpectedInitial);849 850 FunctionPropertiesUpdater FPU(FPI, *CB);851 InlineFunctionInfo IFI;852 auto IR = llvm::InlineFunction(*CB, IFI);853 EXPECT_TRUE(IR.isSuccess());854 invalidate(*F1);855 EXPECT_TRUE(FPU.finishAndTest(FAM));856 857 ExpectedFinal.setFunctionEmbeddingForTest(858 createEmbedder(*F1)->getFunctionVector());859 EXPECT_EQ(FPI, ExpectedFinal);860}861 862TEST_F(FunctionPropertiesAnalysisTest, InvokeSkipLP) {863 LLVMContext C;864 std::unique_ptr<Module> M = makeLLVMModule(C,865 R"IR(866target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"867target triple = "x86_64-pc-linux-gnu"868 869define i64 @f1(i32 noundef %value) {870entry:871 invoke fastcc void @f2() to label %cont unwind label %lpad872cont:873 ret i64 1874lpad:875 %lp = landingpad i32 cleanup876 br label %ehcleanup877ehcleanup:878 resume i32 0879}880define void @f2() {881 invoke noundef void @f3() to label %exit unwind label %lpad882exit:883 ret void884lpad:885 %lp = landingpad i32 cleanup886 resume i32 %lp887}888declare void @f3()889)IR");890 891 // The outcome of inlining will be that lpad becomes unreachable. The landing892 // pad of the invoke inherited from f2 will land on a new bb which will branch893 // to a bb containing the body of lpad.894 Function *F1 = M->getFunction("f1");895 CallBase *CB = findCall(*F1);896 EXPECT_NE(CB, nullptr);897 898 FunctionPropertiesInfo ExpectedInitial;899 ExpectedInitial.BasicBlockCount = 4;900 ExpectedInitial.TotalInstructionCount = 5;901 ExpectedInitial.BlocksReachedFromConditionalInstruction = 0;902 ExpectedInitial.Uses = 1;903 ExpectedInitial.DirectCallsToDefinedFunctions = 1;904 ExpectedInitial.setFunctionEmbeddingForTest(905 createEmbedder(*F1)->getFunctionVector());906 907 FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;908 ExpectedFinal.BasicBlockCount = 6;909 ExpectedFinal.DirectCallsToDefinedFunctions = 0;910 ExpectedFinal.TotalInstructionCount = 8;911 912 auto FPI = buildFPI(*F1);913 EXPECT_EQ(FPI, ExpectedInitial);914 915 FunctionPropertiesUpdater FPU(FPI, *CB);916 InlineFunctionInfo IFI;917 auto IR = llvm::InlineFunction(*CB, IFI);918 EXPECT_TRUE(IR.isSuccess());919 invalidate(*F1);920 EXPECT_TRUE(FPU.finishAndTest(FAM));921 922 ExpectedFinal.setFunctionEmbeddingForTest(923 createEmbedder(*F1)->getFunctionVector());924 EXPECT_EQ(FPI, ExpectedFinal);925}926 927TEST_F(FunctionPropertiesAnalysisTest, DetailedOperandCount) {928 LLVMContext C;929 std::unique_ptr<Module> M = makeLLVMModule(C,930 R"IR(931@a = global i64 1932 933define i64 @f1(i64 %e) {934 %b = load i64, ptr @a935 %c = add i64 %b, 2936 %d = call i64 asm "mov $1,$0", "=r,r" (i64 %c)937 %f = add i64 %d, %e938 ret i64 %f939}940)IR");941 942 Function *F1 = M->getFunction("f1");943 EnableDetailedFunctionProperties.setValue(true);944 FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);945 EXPECT_EQ(DetailedF1Properties.BasicBlocksWithSingleSuccessor, 0);946 EXPECT_EQ(DetailedF1Properties.BasicBlocksWithTwoSuccessors, 0);947 EXPECT_EQ(DetailedF1Properties.BasicBlocksWithMoreThanTwoSuccessors, 0);948 EXPECT_EQ(DetailedF1Properties.BasicBlocksWithSinglePredecessor, 0);949 EXPECT_EQ(DetailedF1Properties.BasicBlocksWithTwoPredecessors, 0);950 EXPECT_EQ(DetailedF1Properties.BasicBlocksWithMoreThanTwoPredecessors, 0);951 EXPECT_EQ(DetailedF1Properties.BigBasicBlocks, 0);952 EXPECT_EQ(DetailedF1Properties.MediumBasicBlocks, 0);953 EXPECT_EQ(DetailedF1Properties.SmallBasicBlocks, 1);954 EXPECT_EQ(DetailedF1Properties.CastInstructionCount, 0);955 EXPECT_EQ(DetailedF1Properties.FloatingPointInstructionCount, 0);956 EXPECT_EQ(DetailedF1Properties.IntegerInstructionCount, 4);957 EXPECT_EQ(DetailedF1Properties.ConstantIntOperandCount, 1);958 EXPECT_EQ(DetailedF1Properties.ConstantFPOperandCount, 0);959 EXPECT_EQ(DetailedF1Properties.ConstantOperandCount, 0);960 EXPECT_EQ(DetailedF1Properties.InstructionOperandCount, 4);961 EXPECT_EQ(DetailedF1Properties.BasicBlockOperandCount, 0);962 EXPECT_EQ(DetailedF1Properties.GlobalValueOperandCount, 1);963 EXPECT_EQ(DetailedF1Properties.InlineAsmOperandCount, 1);964 EXPECT_EQ(DetailedF1Properties.ArgumentOperandCount, 1);965 EXPECT_EQ(DetailedF1Properties.UnknownOperandCount, 0);966 EXPECT_EQ(DetailedF1Properties.CriticalEdgeCount, 0);967 EXPECT_EQ(DetailedF1Properties.ControlFlowEdgeCount, 0);968 EXPECT_EQ(DetailedF1Properties.UnconditionalBranchCount, 0);969 EXPECT_EQ(DetailedF1Properties.IntrinsicCount, 0);970 EXPECT_EQ(DetailedF1Properties.DirectCallCount, 1);971 EXPECT_EQ(DetailedF1Properties.IndirectCallCount, 0);972 EXPECT_EQ(DetailedF1Properties.CallReturnsIntegerCount, 1);973 EXPECT_EQ(DetailedF1Properties.CallReturnsFloatCount, 0);974 EXPECT_EQ(DetailedF1Properties.CallReturnsPointerCount, 0);975 EXPECT_EQ(DetailedF1Properties.CallWithManyArgumentsCount, 0);976 EXPECT_EQ(DetailedF1Properties.CallWithPointerArgumentCount, 0);977 EXPECT_TRUE(DetailedF1Properties.getFunctionEmbedding().approximatelyEquals(978 createEmbedder(*F1)->getFunctionVector()));979 EnableDetailedFunctionProperties.setValue(false);980}981 982TEST_F(FunctionPropertiesAnalysisTest, IntrinsicCount) {983 LLVMContext C;984 std::unique_ptr<Module> M = makeLLVMModule(C,985 R"IR(986define float @f1(float %a) {987 %b = call float @llvm.cos.f32(float %a)988 ret float %b989}990declare float @llvm.cos.f32(float)991)IR");992 993 Function *F1 = M->getFunction("f1");994 EnableDetailedFunctionProperties.setValue(true);995 FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);996 EXPECT_EQ(DetailedF1Properties.IntrinsicCount, 1);997 EXPECT_EQ(DetailedF1Properties.DirectCallCount, 1);998 EXPECT_EQ(DetailedF1Properties.IndirectCallCount, 0);999 EXPECT_EQ(DetailedF1Properties.CallReturnsIntegerCount, 0);1000 EXPECT_EQ(DetailedF1Properties.CallReturnsFloatCount, 1);1001 EXPECT_EQ(DetailedF1Properties.CallReturnsPointerCount, 0);1002 EXPECT_EQ(DetailedF1Properties.CallWithManyArgumentsCount, 0);1003 EXPECT_EQ(DetailedF1Properties.CallWithPointerArgumentCount, 0);1004 EXPECT_TRUE(DetailedF1Properties.getFunctionEmbedding().approximatelyEquals(1005 createEmbedder(*F1)->getFunctionVector()));1006 EnableDetailedFunctionProperties.setValue(false);1007}1008 1009TEST_F(FunctionPropertiesAnalysisTest, FunctionCallMetrics) {1010 LLVMContext C;1011 std::unique_ptr<Module> M = makeLLVMModule(C,1012 R"IR(1013define i64 @f1(i64 %a) {1014 %b = call i64 @f2(i64 %a, i64 %a, i64 %a, i64 %a, i64 %a)1015 %c = call ptr @f3()1016 call void @f4(ptr %c)1017 %d = call float @f5()1018 %e = call i64 %c(i64 %b)1019 ret i64 %b1020}1021 1022declare i64 @f2(i64,i64,i64,i64,i64)1023declare ptr @f3()1024declare void @f4(ptr)1025declare float @f5()1026)IR");1027 1028 Function *F1 = M->getFunction("f1");1029 EnableDetailedFunctionProperties.setValue(true);1030 FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);1031 EXPECT_EQ(DetailedF1Properties.IntrinsicCount, 0);1032 EXPECT_EQ(DetailedF1Properties.DirectCallCount, 4);1033 EXPECT_EQ(DetailedF1Properties.IndirectCallCount, 1);1034 EXPECT_EQ(DetailedF1Properties.CallReturnsIntegerCount, 2);1035 EXPECT_EQ(DetailedF1Properties.CallReturnsFloatCount, 1);1036 EXPECT_EQ(DetailedF1Properties.CallReturnsPointerCount, 1);1037 EXPECT_EQ(DetailedF1Properties.CallWithManyArgumentsCount, 1);1038 EXPECT_EQ(DetailedF1Properties.CallWithPointerArgumentCount, 1);1039 EXPECT_TRUE(DetailedF1Properties.getFunctionEmbedding().approximatelyEquals(1040 createEmbedder(*F1)->getFunctionVector()));1041 EnableDetailedFunctionProperties.setValue(false);1042}1043 1044TEST_F(FunctionPropertiesAnalysisTest, CriticalEdge) {1045 LLVMContext C;1046 std::unique_ptr<Module> M = makeLLVMModule(C,1047 R"IR(1048define i64 @f1(i64 %a) {1049 %b = icmp eq i64 %a, 11050 br i1 %b, label %TopBlock1, label %TopBlock21051TopBlock1:1052 %c = add i64 %a, 11053 %e = icmp eq i64 %c, 21054 br i1 %e, label %BottomBlock1, label %BottomBlock21055TopBlock2:1056 %d = add i64 %a, 21057 br label %BottomBlock21058BottomBlock1:1059 ret i64 01060BottomBlock2:1061 %f = phi i64 [ %c, %TopBlock1 ], [ %d, %TopBlock2 ]1062 ret i64 %f1063}1064)IR");1065 1066 Function *F1 = M->getFunction("f1");1067 EnableDetailedFunctionProperties.setValue(true);1068 FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);1069 EXPECT_EQ(DetailedF1Properties.CriticalEdgeCount, 1);1070 EXPECT_TRUE(DetailedF1Properties.getFunctionEmbedding().approximatelyEquals(1071 createEmbedder(*F1)->getFunctionVector()));1072 EnableDetailedFunctionProperties.setValue(false);1073}1074 1075TEST_F(FunctionPropertiesAnalysisTest, FunctionReturnVectors) {1076 LLVMContext C;1077 std::unique_ptr<Module> M = makeLLVMModule(C,1078 R"IR(1079define <4 x i64> @f1(<4 x i64> %a) {1080 %b = call <4 x i64> @f2()1081 %c = call <4 x float> @f3()1082 %d = call <4 x ptr> @f4()1083 ret <4 x i64> %b1084}1085 1086declare <4 x i64> @f2()1087declare <4 x float> @f3()1088declare <4 x ptr> @f4()1089)IR");1090 1091 Function *F1 = M->getFunction("f1");1092 EnableDetailedFunctionProperties.setValue(true);1093 FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);1094 EXPECT_EQ(DetailedF1Properties.CallReturnsVectorIntCount, 1);1095 EXPECT_EQ(DetailedF1Properties.CallReturnsVectorFloatCount, 1);1096 EXPECT_EQ(DetailedF1Properties.CallReturnsVectorPointerCount, 1);1097 EXPECT_TRUE(DetailedF1Properties.getFunctionEmbedding().approximatelyEquals(1098 createEmbedder(*F1)->getFunctionVector()));1099 EnableDetailedFunctionProperties.setValue(false);1100}1101 1102TEST_F(FunctionPropertiesAnalysisTest, ReAddEdges) {1103 LLVMContext C;1104 std::unique_ptr<Module> M = makeLLVMModule(C, R"IR(1105define hidden void @f1(ptr noundef %destatep, i32 noundef %offset, i8 noundef zeroext %byte1) {1106entry:1107 %cmp = icmp eq i8 %byte1, 01108 br i1 %cmp, label %if.then, label %if.else1109 1110if.then: ; preds = %entry1111 call fastcc void @f2(ptr noundef %destatep, i32 noundef 37, i32 noundef 600)1112 %and = and i32 %offset, 31113 switch i32 %and, label %default.unreachable [1114 i32 0, label %sw.bb1115 i32 1, label %sw.bb11116 i32 2, label %sw.bb11117 i32 3, label %if.end1118 ]1119 1120sw.bb: ; preds = %if.then1121 call fastcc void @f2(ptr noundef %destatep, i32 noundef 57, i32 noundef 600)1122 br label %if.end1123 1124sw.bb1: ; preds = %if.then, %if.then1125 call fastcc void @f2(ptr noundef %destatep, i32 noundef 56, i32 noundef 600) #341126 br label %if.end1127 1128default.unreachable: ; preds = %if.then1129 unreachable1130 1131if.else: ; preds = %entry1132 call fastcc void @f2(ptr noundef %destatep, i32 noundef 56, i32 noundef 600)1133 br label %if.end1134 1135if.end: ; preds = %sw.bb, %sw.bb1, %if.then, %if.else1136 ret void1137}1138 1139define internal fastcc void @f2(ptr nocapture noundef %destatep, i32 noundef %r_enc, i32 noundef %whack) {1140entry:1141 %enc_prob = getelementptr inbounds nuw i8, ptr %destatep, i32 5121142 %arrayidx = getelementptr inbounds [67 x i32], ptr %enc_prob, i32 0, i32 %r_enc1143 %0 = load i32, ptr %arrayidx, align 41144 %sub = sub nsw i32 %0, %whack1145 store i32 %sub, ptr %arrayidx, align 41146 ret void1147}1148 )IR");1149 auto *F1 = M->getFunction("f1");1150 auto *F2 = M->getFunction("f2");1151 auto *CB = [&]() -> CallBase * {1152 for (auto &BB : *F1)1153 for (auto &I : BB)1154 if (auto *CB = dyn_cast<CallBase>(&I);1155 CB && CB->getCalledFunction() && CB->getCalledFunction() == F2)1156 return CB;1157 return nullptr;1158 }();1159 ASSERT_NE(CB, nullptr);1160 auto FPI = buildFPI(*F1);1161 FunctionPropertiesUpdater FPU(FPI, *CB);1162 InlineFunctionInfo IFI;1163 auto IR = llvm::InlineFunction(*CB, IFI);1164 EXPECT_TRUE(IR.isSuccess());1165 invalidate(*F1);1166 EXPECT_TRUE(FPU.finishAndTest(FAM));1167}1168 1169TEST_F(FunctionPropertiesAnalysisTest, InvokeLandingCanStillBeReached) {1170 LLVMContext C;1171 // %lpad is reachable from a block not involved in the inlining decision. We1172 // make sure that's not the entry - otherwise the DT will be recomputed from1173 // scratch. The idea here is that the edge known to the inliner to potentially1174 // disappear - %lpad->%ehcleanup -should survive because it is still reachable1175 // from %middle.1176 std::unique_ptr<Module> M = makeLLVMModule(C,1177 R"IR(1178target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"1179target triple = "x86_64-pc-linux-gnu"1180 1181define i64 @f1(i32 noundef %value) {1182entry:1183 br label %middle1184middle:1185 %c = icmp eq i32 %value, 01186 br i1 %c, label %invoke, label %lpad1187invoke:1188 invoke fastcc void @f2() to label %cont unwind label %lpad1189cont:1190 br label %exit1191lpad:1192 %lp = landingpad i32 cleanup1193 br label %ehcleanup1194ehcleanup:1195 resume i32 01196exit:1197 ret i64 11198}1199define void @f2() {1200 ret void1201}1202)IR");1203 1204 Function *F1 = M->getFunction("f1");1205 CallBase *CB = findCall(*F1);1206 EXPECT_NE(CB, nullptr);1207 1208 auto FPI = buildFPI(*F1);1209 FunctionPropertiesUpdater FPU(FPI, *CB);1210 InlineFunctionInfo IFI;1211 auto IR = llvm::InlineFunction(*CB, IFI);1212 EXPECT_TRUE(IR.isSuccess());1213 invalidate(*F1);1214 EXPECT_TRUE(FPU.finishAndTest(FAM));1215}1216} // end anonymous namespace1217