brintos

brintos / llvm-project-archived public Read only

0
0
Text · 20.9 KiB · b642f37 Raw
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