611 lines · cpp
1//===- CallPromotionUtilsTest.cpp - CallPromotionUtils 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/Transforms/Utils/CallPromotionUtils.h"10#include "llvm/Analysis/CtxProfAnalysis.h"11#include "llvm/AsmParser/Parser.h"12#include "llvm/IR/IRBuilder.h"13#include "llvm/IR/Instructions.h"14#include "llvm/IR/LLVMContext.h"15#include "llvm/IR/MDBuilder.h"16#include "llvm/IR/Module.h"17#include "llvm/IR/NoFolder.h"18#include "llvm/IR/PassInstrumentation.h"19#include "llvm/ProfileData/PGOCtxProfReader.h"20#include "llvm/ProfileData/PGOCtxProfWriter.h"21#include "llvm/Support/SourceMgr.h"22#include "llvm/Support/raw_ostream.h"23#include "llvm/Testing/Support/SupportHelpers.h"24#include "gtest/gtest.h"25 26using namespace llvm;27 28static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {29 SMDiagnostic Err;30 std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);31 if (!Mod)32 Err.print("UtilsTests", errs());33 return Mod;34}35 36// Returns a constant representing the vtable's address point specified by the37// offset.38static Constant *getVTableAddressPointOffset(GlobalVariable *VTable,39 uint32_t AddressPointOffset) {40 Module &M = *VTable->getParent();41 LLVMContext &Context = M.getContext();42 assert(AddressPointOffset <43 M.getDataLayout().getTypeAllocSize(VTable->getValueType()) &&44 "Out-of-bound access");45 46 return ConstantExpr::getInBoundsGetElementPtr(47 Type::getInt8Ty(Context), VTable,48 llvm::ConstantInt::get(Type::getInt32Ty(Context), AddressPointOffset));49}50 51TEST(CallPromotionUtilsTest, TryPromoteCall) {52 LLVMContext C;53 std::unique_ptr<Module> M = parseIR(C,54 R"IR(55%class.Impl = type <{ %class.Interface, i32, [4 x i8] }>56%class.Interface = type { i32 (...)** }57 58@_ZTV4Impl = constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (void (%class.Impl*)* @_ZN4Impl3RunEv to i8*)] }59 60define void @f() {61entry:62 %o = alloca %class.Impl63 %base = getelementptr %class.Impl, %class.Impl* %o, i64 0, i32 0, i32 064 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV4Impl, i64 0, i32 0, i64 2) to i32 (...)**), i32 (...)*** %base65 %f = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 166 store i32 3, i32* %f67 %base.i = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 068 %c = bitcast %class.Interface* %base.i to void (%class.Interface*)***69 %vtable.i = load void (%class.Interface*)**, void (%class.Interface*)*** %c70 %fp = load void (%class.Interface*)*, void (%class.Interface*)** %vtable.i71 call void %fp(%class.Interface* nonnull %base.i)72 ret void73}74 75declare void @_ZN4Impl3RunEv(%class.Impl* %this)76)IR");77 78 auto *GV = M->getNamedValue("f");79 ASSERT_TRUE(GV);80 auto *F = dyn_cast<Function>(GV);81 ASSERT_TRUE(F);82 Instruction *Inst = &F->front().front();83 auto *AI = dyn_cast<AllocaInst>(Inst);84 ASSERT_TRUE(AI);85 Inst = &*++F->front().rbegin();86 auto *CI = dyn_cast<CallInst>(Inst);87 ASSERT_TRUE(CI);88 ASSERT_FALSE(CI->getCalledFunction());89 bool IsPromoted = tryPromoteCall(*CI);90 EXPECT_TRUE(IsPromoted);91 GV = M->getNamedValue("_ZN4Impl3RunEv");92 ASSERT_TRUE(GV);93 auto *F1 = dyn_cast<Function>(GV);94 EXPECT_EQ(F1, CI->getCalledFunction());95}96 97TEST(CallPromotionUtilsTest, TryPromoteCall_NoFPLoad) {98 LLVMContext C;99 std::unique_ptr<Module> M = parseIR(C,100 R"IR(101%class.Impl = type <{ %class.Interface, i32, [4 x i8] }>102%class.Interface = type { i32 (...)** }103 104define void @f(void (%class.Interface*)* %fp, %class.Interface* nonnull %base.i) {105entry:106 call void %fp(%class.Interface* nonnull %base.i)107 ret void108}109)IR");110 111 auto *GV = M->getNamedValue("f");112 ASSERT_TRUE(GV);113 auto *F = dyn_cast<Function>(GV);114 ASSERT_TRUE(F);115 Instruction *Inst = &F->front().front();116 auto *CI = dyn_cast<CallInst>(Inst);117 ASSERT_TRUE(CI);118 ASSERT_FALSE(CI->getCalledFunction());119 bool IsPromoted = tryPromoteCall(*CI);120 EXPECT_FALSE(IsPromoted);121}122 123TEST(CallPromotionUtilsTest, TryPromoteCall_NoVTablePtrLoad) {124 LLVMContext C;125 std::unique_ptr<Module> M = parseIR(C,126 R"IR(127%class.Impl = type <{ %class.Interface, i32, [4 x i8] }>128%class.Interface = type { i32 (...)** }129 130define void @f(void (%class.Interface*)** %vtable.i, %class.Interface* nonnull %base.i) {131entry:132 %fp = load void (%class.Interface*)*, void (%class.Interface*)** %vtable.i133 call void %fp(%class.Interface* nonnull %base.i)134 ret void135}136)IR");137 138 auto *GV = M->getNamedValue("f");139 ASSERT_TRUE(GV);140 auto *F = dyn_cast<Function>(GV);141 ASSERT_TRUE(F);142 Instruction *Inst = &*++F->front().rbegin();143 auto *CI = dyn_cast<CallInst>(Inst);144 ASSERT_TRUE(CI);145 ASSERT_FALSE(CI->getCalledFunction());146 bool IsPromoted = tryPromoteCall(*CI);147 EXPECT_FALSE(IsPromoted);148}149 150TEST(CallPromotionUtilsTest, TryPromoteCall_NoVTableInitFound) {151 LLVMContext C;152 std::unique_ptr<Module> M = parseIR(C,153 R"IR(154%class.Impl = type <{ %class.Interface, i32, [4 x i8] }>155%class.Interface = type { i32 (...)** }156 157define void @f() {158entry:159 %o = alloca %class.Impl160 %f = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 1161 store i32 3, i32* %f162 %base.i = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 0163 %c = bitcast %class.Interface* %base.i to void (%class.Interface*)***164 %vtable.i = load void (%class.Interface*)**, void (%class.Interface*)*** %c165 %fp = load void (%class.Interface*)*, void (%class.Interface*)** %vtable.i166 call void %fp(%class.Interface* nonnull %base.i)167 ret void168}169 170declare void @_ZN4Impl3RunEv(%class.Impl* %this)171)IR");172 173 auto *GV = M->getNamedValue("f");174 ASSERT_TRUE(GV);175 auto *F = dyn_cast<Function>(GV);176 ASSERT_TRUE(F);177 Instruction *Inst = &*++F->front().rbegin();178 auto *CI = dyn_cast<CallInst>(Inst);179 ASSERT_TRUE(CI);180 ASSERT_FALSE(CI->getCalledFunction());181 bool IsPromoted = tryPromoteCall(*CI);182 EXPECT_FALSE(IsPromoted);183}184 185TEST(CallPromotionUtilsTest, TryPromoteCall_EmptyVTable) {186 LLVMContext C;187 std::unique_ptr<Module> M = parseIR(C,188 R"IR(189%class.Impl = type <{ %class.Interface, i32, [4 x i8] }>190%class.Interface = type { i32 (...)** }191 192@_ZTV4Impl = external global { [3 x i8*] }193 194define void @f() {195entry:196 %o = alloca %class.Impl197 %base = getelementptr %class.Impl, %class.Impl* %o, i64 0, i32 0, i32 0198 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV4Impl, i64 0, i32 0, i64 2) to i32 (...)**), i32 (...)*** %base199 %f = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 1200 store i32 3, i32* %f201 %base.i = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 0202 %c = bitcast %class.Interface* %base.i to void (%class.Interface*)***203 %vtable.i = load void (%class.Interface*)**, void (%class.Interface*)*** %c204 %fp = load void (%class.Interface*)*, void (%class.Interface*)** %vtable.i205 call void %fp(%class.Interface* nonnull %base.i)206 ret void207}208 209declare void @_ZN4Impl3RunEv(%class.Impl* %this)210)IR");211 212 auto *GV = M->getNamedValue("f");213 ASSERT_TRUE(GV);214 auto *F = dyn_cast<Function>(GV);215 ASSERT_TRUE(F);216 Instruction *Inst = &F->front().front();217 auto *AI = dyn_cast<AllocaInst>(Inst);218 ASSERT_TRUE(AI);219 Inst = &*++F->front().rbegin();220 auto *CI = dyn_cast<CallInst>(Inst);221 ASSERT_TRUE(CI);222 ASSERT_FALSE(CI->getCalledFunction());223 bool IsPromoted = tryPromoteCall(*CI);224 EXPECT_FALSE(IsPromoted);225}226 227TEST(CallPromotionUtilsTest, TryPromoteCall_NullFP) {228 LLVMContext C;229 std::unique_ptr<Module> M = parseIR(C,230 R"IR(231%class.Impl = type <{ %class.Interface, i32, [4 x i8] }>232%class.Interface = type { i32 (...)** }233 234@_ZTV4Impl = constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* null] }235 236define void @f() {237entry:238 %o = alloca %class.Impl239 %base = getelementptr %class.Impl, %class.Impl* %o, i64 0, i32 0, i32 0240 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV4Impl, i64 0, i32 0, i64 2) to i32 (...)**), i32 (...)*** %base241 %f = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 1242 store i32 3, i32* %f243 %base.i = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 0244 %c = bitcast %class.Interface* %base.i to void (%class.Interface*)***245 %vtable.i = load void (%class.Interface*)**, void (%class.Interface*)*** %c246 %fp = load void (%class.Interface*)*, void (%class.Interface*)** %vtable.i247 call void %fp(%class.Interface* nonnull %base.i)248 ret void249}250 251declare void @_ZN4Impl3RunEv(%class.Impl* %this)252)IR");253 254 auto *GV = M->getNamedValue("f");255 ASSERT_TRUE(GV);256 auto *F = dyn_cast<Function>(GV);257 ASSERT_TRUE(F);258 Instruction *Inst = &F->front().front();259 auto *AI = dyn_cast<AllocaInst>(Inst);260 ASSERT_TRUE(AI);261 Inst = &*++F->front().rbegin();262 auto *CI = dyn_cast<CallInst>(Inst);263 ASSERT_TRUE(CI);264 ASSERT_FALSE(CI->getCalledFunction());265 bool IsPromoted = tryPromoteCall(*CI);266 EXPECT_FALSE(IsPromoted);267}268 269// Based on clang/test/CodeGenCXX/member-function-pointer-calls.cpp270TEST(CallPromotionUtilsTest, TryPromoteCall_MemberFunctionCalls) {271 LLVMContext C;272 std::unique_ptr<Module> M = parseIR(C,273 R"IR(274%struct.A = type { i32 (...)** }275 276@_ZTV1A = linkonce_odr unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%struct.A*)* @_ZN1A3vf1Ev to i8*), i8* bitcast (i32 (%struct.A*)* @_ZN1A3vf2Ev to i8*)] }, align 8277 278define i32 @_Z2g1v() {279entry:280 %a = alloca %struct.A, align 8281 %0 = bitcast %struct.A* %a to i8*282 %1 = getelementptr %struct.A, %struct.A* %a, i64 0, i32 0283 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [4 x i8*] }, { [4 x i8*] }* @_ZTV1A, i64 0, i32 0, i64 2) to i32 (...)**), i32 (...)*** %1, align 8284 %2 = bitcast %struct.A* %a to i8*285 %3 = bitcast i8* %2 to i8**286 %vtable.i = load i8*, i8** %3, align 8287 %4 = bitcast i8* %vtable.i to i32 (%struct.A*)**288 %memptr.virtualfn.i = load i32 (%struct.A*)*, i32 (%struct.A*)** %4, align 8289 %call.i = call i32 %memptr.virtualfn.i(%struct.A* %a)290 ret i32 %call.i291}292 293define i32 @_Z2g2v() {294entry:295 %a = alloca %struct.A, align 8296 %0 = bitcast %struct.A* %a to i8*297 %1 = getelementptr %struct.A, %struct.A* %a, i64 0, i32 0298 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [4 x i8*] }, { [4 x i8*] }* @_ZTV1A, i64 0, i32 0, i64 2) to i32 (...)**), i32 (...)*** %1, align 8299 %2 = bitcast %struct.A* %a to i8*300 %3 = bitcast i8* %2 to i8**301 %vtable.i = load i8*, i8** %3, align 8302 %4 = getelementptr i8, i8* %vtable.i, i64 8303 %5 = bitcast i8* %4 to i32 (%struct.A*)**304 %memptr.virtualfn.i = load i32 (%struct.A*)*, i32 (%struct.A*)** %5, align 8305 %call.i = call i32 %memptr.virtualfn.i(%struct.A* %a)306 ret i32 %call.i307}308 309declare i32 @_ZN1A3vf1Ev(%struct.A* %this)310declare i32 @_ZN1A3vf2Ev(%struct.A* %this)311)IR");312 313 auto *GV = M->getNamedValue("_Z2g1v");314 ASSERT_TRUE(GV);315 auto *F = dyn_cast<Function>(GV);316 ASSERT_TRUE(F);317 Instruction *Inst = &F->front().front();318 auto *AI = dyn_cast<AllocaInst>(Inst);319 ASSERT_TRUE(AI);320 Inst = &*++F->front().rbegin();321 auto *CI = dyn_cast<CallInst>(Inst);322 ASSERT_TRUE(CI);323 ASSERT_FALSE(CI->getCalledFunction());324 bool IsPromoted1 = tryPromoteCall(*CI);325 EXPECT_TRUE(IsPromoted1);326 GV = M->getNamedValue("_ZN1A3vf1Ev");327 ASSERT_TRUE(GV);328 F = dyn_cast<Function>(GV);329 EXPECT_EQ(F, CI->getCalledFunction());330 331 GV = M->getNamedValue("_Z2g2v");332 ASSERT_TRUE(GV);333 F = dyn_cast<Function>(GV);334 ASSERT_TRUE(F);335 Inst = &F->front().front();336 AI = dyn_cast<AllocaInst>(Inst);337 ASSERT_TRUE(AI);338 Inst = &*++F->front().rbegin();339 CI = dyn_cast<CallInst>(Inst);340 ASSERT_TRUE(CI);341 ASSERT_FALSE(CI->getCalledFunction());342 bool IsPromoted2 = tryPromoteCall(*CI);343 EXPECT_TRUE(IsPromoted2);344 GV = M->getNamedValue("_ZN1A3vf2Ev");345 ASSERT_TRUE(GV);346 F = dyn_cast<Function>(GV);347 EXPECT_EQ(F, CI->getCalledFunction());348}349 350// Check that it isn't crashing due to missing promotion legality.351TEST(CallPromotionUtilsTest, TryPromoteCall_Legality) {352 LLVMContext C;353 std::unique_ptr<Module> M = parseIR(C,354 R"IR(355%struct1 = type <{ i32, i64 }>356%struct2 = type <{ i32, i64 }>357 358%class.Impl = type <{ %class.Interface, i32, [4 x i8] }>359%class.Interface = type { i32 (...)** }360 361@_ZTV4Impl = constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (%struct2 (%class.Impl*)* @_ZN4Impl3RunEv to i8*)] }362 363define %struct1 @f() {364entry:365 %o = alloca %class.Impl366 %base = getelementptr %class.Impl, %class.Impl* %o, i64 0, i32 0, i32 0367 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV4Impl, i64 0, i32 0, i64 2) to i32 (...)**), i32 (...)*** %base368 %f = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 1369 store i32 3, i32* %f370 %base.i = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 0371 %c = bitcast %class.Interface* %base.i to %struct1 (%class.Interface*)***372 %vtable.i = load %struct1 (%class.Interface*)**, %struct1 (%class.Interface*)*** %c373 %fp = load %struct1 (%class.Interface*)*, %struct1 (%class.Interface*)** %vtable.i374 %rv = call %struct1 %fp(%class.Interface* nonnull %base.i)375 ret %struct1 %rv376}377 378declare %struct2 @_ZN4Impl3RunEv(%class.Impl* %this)379)IR");380 381 auto *GV = M->getNamedValue("f");382 ASSERT_TRUE(GV);383 auto *F = dyn_cast<Function>(GV);384 ASSERT_TRUE(F);385 Instruction *Inst = &F->front().front();386 auto *AI = dyn_cast<AllocaInst>(Inst);387 ASSERT_TRUE(AI);388 Inst = &*++F->front().rbegin();389 auto *CI = dyn_cast<CallInst>(Inst);390 ASSERT_TRUE(CI);391 ASSERT_FALSE(CI->getCalledFunction());392 bool IsPromoted = tryPromoteCall(*CI);393 EXPECT_FALSE(IsPromoted);394}395 396TEST(CallPromotionUtilsTest, promoteCallWithVTableCmp) {397 LLVMContext C;398 std::unique_ptr<Module> M = parseIR(C,399 R"IR(400target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"401target triple = "x86_64-unknown-linux-gnu"402 403@_ZTV5Base1 = constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr null, ptr @_ZN5Base15func0Ev, ptr @_ZN5Base15func1Ev] }, !type !0404@_ZTV8Derived1 = constant { [4 x ptr], [3 x ptr] } { [4 x ptr] [ptr inttoptr (i64 -8 to ptr), ptr null, ptr @_ZN5Base15func0Ev, ptr @_ZN5Base15func1Ev], [3 x ptr] [ptr null, ptr null, ptr @_ZN5Base25func2Ev] }, !type !0, !type !1, !type !2405@_ZTV8Derived2 = constant { [3 x ptr], [3 x ptr], [4 x ptr] } { [3 x ptr] [ptr null, ptr null, ptr @_ZN5Base35func3Ev], [3 x ptr] [ptr inttoptr (i64 -8 to ptr), ptr null, ptr @_ZN5Base25func2Ev], [4 x ptr] [ptr inttoptr (i64 -16 to ptr), ptr null, ptr @_ZN5Base15func0Ev, ptr @_ZN5Base15func1Ev] }, !type !3, !type !4, !type !5, !type !6406 407define i32 @testfunc(ptr %d) {408entry:409 %vtable = load ptr, ptr %d, !prof !7410 %vfn = getelementptr inbounds ptr, ptr %vtable, i64 1411 %0 = load ptr, ptr %vfn412 %call = tail call i32 %0(ptr %d), !prof !8413 ret i32 %call414}415 416define i32 @_ZN5Base15func1Ev(ptr %this) {417entry:418 ret i32 2419}420 421declare i32 @_ZN5Base25func2Ev(ptr)422declare i32 @_ZN5Base15func0Ev(ptr)423declare void @_ZN5Base35func3Ev(ptr)424 425!0 = !{i64 16, !"_ZTS5Base1"}426!1 = !{i64 48, !"_ZTS5Base2"}427!2 = !{i64 16, !"_ZTS8Derived1"}428!3 = !{i64 64, !"_ZTS5Base1"}429!4 = !{i64 40, !"_ZTS5Base2"}430!5 = !{i64 16, !"_ZTS5Base3"}431!6 = !{i64 16, !"_ZTS8Derived2"}432!7 = !{!"VP", i32 2, i64 1600, i64 -9064381665493407289, i64 800, i64 5035968517245772950, i64 500, i64 3215870116411581797, i64 300}433!8 = !{!"VP", i32 0, i64 1600, i64 6804820478065511155, i64 1600})IR");434 435 Function *F = M->getFunction("testfunc");436 CallInst *CI = dyn_cast<CallInst>(&*std::next(F->front().rbegin()));437 ASSERT_TRUE(CI && CI->isIndirectCall());438 439 // Create the constant and the branch weights440 SmallVector<Constant *, 3> VTableAddressPoints;441 442 for (auto &[VTableName, AddressPointOffset] : {std::pair{"_ZTV5Base1", 16},443 {"_ZTV8Derived1", 16},444 {"_ZTV8Derived2", 64}})445 VTableAddressPoints.push_back(getVTableAddressPointOffset(446 M->getGlobalVariable(VTableName), AddressPointOffset));447 448 MDBuilder MDB(C);449 MDNode *BranchWeights = MDB.createBranchWeights(1600, 0);450 451 size_t OrigEntryBBSize = F->front().size();452 453 LoadInst *VPtr = dyn_cast<LoadInst>(&*F->front().begin());454 455 Function *Callee = M->getFunction("_ZN5Base15func1Ev");456 // Tests that promoted direct call is returned.457 CallBase &DirectCB = promoteCallWithVTableCmp(458 *CI, VPtr, Callee, VTableAddressPoints, BranchWeights);459 EXPECT_EQ(DirectCB.getCalledOperand(), Callee);460 461 // Promotion inserts 3 icmp instructions and 2 or instructions, and removes462 // 1 call instruction from the entry block.463 EXPECT_EQ(F->front().size(), OrigEntryBBSize + 4);464}465 466TEST(CallPromotionUtilsTest, PromoteWithIcmpAndCtxProf) {467 LLVMContext C;468 std::unique_ptr<Module> M = parseIR(C,469 R"IR(470define i32 @testfunc1(ptr %d) !guid !0 {471 call void @llvm.instrprof.increment(ptr @testfunc1, i64 0, i32 1, i32 0)472 call void @llvm.instrprof.callsite(ptr @testfunc1, i64 0, i32 1, i32 0, ptr %d)473 %call = call i32 %d()474 ret i32 %call475}476 477define i32 @f1() !guid !1 {478 call void @llvm.instrprof.increment(ptr @f1, i64 0, i32 1, i32 0)479 ret i32 2480}481 482define i32 @f2() !guid !2 {483 call void @llvm.instrprof.increment(ptr @f2, i64 0, i32 1, i32 0)484 call void @llvm.instrprof.callsite(ptr @f2, i64 0, i32 1, i32 0, ptr @f4)485 %r = call i32 @f4()486 ret i32 %r487}488 489define i32 @testfunc2(ptr %p) !guid !4 {490 call void @llvm.instrprof.increment(ptr @testfunc2, i64 0, i32 1, i32 0)491 call void @llvm.instrprof.callsite(ptr @testfunc2, i64 0, i32 1, i32 0, ptr @testfunc1)492 %r = call i32 @testfunc1(ptr %p)493 ret i32 %r494}495 496declare i32 @f3()497 498define i32 @f4() !guid !3 {499 ret i32 3500}501 502!0 = !{i64 1000}503!1 = !{i64 1001}504!2 = !{i64 1002}505!3 = !{i64 1004}506!4 = !{i64 1005}507)IR");508 509 const char *Profile = R"json(510 { "Contexts":511 [512 {513 "Guid": 1000,514 "TotalRootEntryCount": 1,515 "Counters": [1],516 "Callsites": [517 [{ "Guid": 1001,518 "Counters": [10]}, 519 { "Guid": 1002,520 "Counters": [11],521 "Callsites": [[{"Guid": 1004, "Counters":[13]}]]522 },523 { "Guid": 1003,524 "Counters": [12]525 }]]526 },527 {528 "Guid": 1005,529 "TotalRootEntryCount": 1,530 "Counters": [2],531 "Callsites": [532 [{ "Guid": 1000,533 "Counters": [1],534 "Callsites": [535 [{ "Guid": 1001,536 "Counters": [101]}, 537 { "Guid": 1002,538 "Counters": [102],539 "Callsites": [[{"Guid": 1004, "Counters":[104]}]]540 },541 { "Guid": 1003,542 "Counters": [103]543 }]]}]]}]}544 )json";545 546 llvm::unittest::TempFile ProfileFile("ctx_profile", "", "", /*Unique=*/true);547 {548 std::error_code EC;549 raw_fd_stream Out(ProfileFile.path(), EC);550 ASSERT_FALSE(EC);551 // "False" means no error.552 ASSERT_FALSE(llvm::createCtxProfFromYAML(Profile, Out));553 }554 555 ModuleAnalysisManager MAM;556 MAM.registerPass([&]() { return CtxProfAnalysis(ProfileFile.path()); });557 MAM.registerPass([&]() { return PassInstrumentationAnalysis(); });558 auto &CtxProf = MAM.getResult<CtxProfAnalysis>(*M);559 auto *Caller = M->getFunction("testfunc1");560 ASSERT_NE(Caller, nullptr);561 auto *Callee = M->getFunction("f2");562 ASSERT_NE(Callee, nullptr);563 auto *IndirectCS = [&]() -> CallBase * {564 for (auto &BB : *Caller)565 for (auto &I : BB)566 if (auto *CB = dyn_cast<CallBase>(&I); CB && CB->isIndirectCall())567 return CB;568 return nullptr;569 }();570 ASSERT_NE(IndirectCS, nullptr);571 promoteCallWithIfThenElse(*IndirectCS, *Callee, CtxProf);572 573 std::string Str;574 raw_string_ostream OS(Str);575 CtxProfAnalysisPrinterPass Printer(OS);576 Printer.run(*M, MAM);577 const char *Expected = R"yaml(578Contexts:579 - Guid: 1000580 TotalRootEntryCount: 1581 Counters: [ 1, 11, 22 ]582 Callsites:583 - - Guid: 1001584 Counters: [ 10 ]585 - Guid: 1003586 Counters: [ 12 ]587 - - Guid: 1002588 Counters: [ 11 ]589 Callsites:590 - - Guid: 1004591 Counters: [ 13 ]592 - Guid: 1005593 TotalRootEntryCount: 1594 Counters: [ 2 ]595 Callsites:596 - - Guid: 1000597 Counters: [ 1, 102, 204 ]598 Callsites:599 - - Guid: 1001600 Counters: [ 101 ]601 - Guid: 1003602 Counters: [ 103 ]603 - - Guid: 1002604 Counters: [ 102 ]605 Callsites:606 - - Guid: 1004607 Counters: [ 104 ]608)yaml";609 EXPECT_EQ(Expected, Str);610}611