1bb383ae6SHiroshi Yamauchi //===- CallPromotionUtilsTest.cpp - CallPromotionUtils unit tests ---------===// 2bb383ae6SHiroshi Yamauchi // 3bb383ae6SHiroshi Yamauchi // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bb383ae6SHiroshi Yamauchi // See https://llvm.org/LICENSE.txt for license information. 5bb383ae6SHiroshi Yamauchi // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bb383ae6SHiroshi Yamauchi // 7bb383ae6SHiroshi Yamauchi //===----------------------------------------------------------------------===// 8bb383ae6SHiroshi Yamauchi 9bb383ae6SHiroshi Yamauchi #include "llvm/Transforms/Utils/CallPromotionUtils.h" 1073c3b733SMircea Trofin #include "llvm/Analysis/CtxProfAnalysis.h" 11bb383ae6SHiroshi Yamauchi #include "llvm/AsmParser/Parser.h" 125d3f2967SMingming Liu #include "llvm/IR/IRBuilder.h" 13bb383ae6SHiroshi Yamauchi #include "llvm/IR/Instructions.h" 14bb383ae6SHiroshi Yamauchi #include "llvm/IR/LLVMContext.h" 155d3f2967SMingming Liu #include "llvm/IR/MDBuilder.h" 16bb383ae6SHiroshi Yamauchi #include "llvm/IR/Module.h" 175d3f2967SMingming Liu #include "llvm/IR/NoFolder.h" 1873c3b733SMircea Trofin #include "llvm/IR/PassInstrumentation.h" 1973c3b733SMircea Trofin #include "llvm/ProfileData/PGOCtxProfReader.h" 2073c3b733SMircea Trofin #include "llvm/ProfileData/PGOCtxProfWriter.h" 21bb383ae6SHiroshi Yamauchi #include "llvm/Support/SourceMgr.h" 2273c3b733SMircea Trofin #include "llvm/Support/raw_ostream.h" 2373c3b733SMircea Trofin #include "llvm/Testing/Support/SupportHelpers.h" 24bb383ae6SHiroshi Yamauchi #include "gtest/gtest.h" 25bb383ae6SHiroshi Yamauchi 26bb383ae6SHiroshi Yamauchi using namespace llvm; 27bb383ae6SHiroshi Yamauchi 28bb383ae6SHiroshi Yamauchi static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { 29bb383ae6SHiroshi Yamauchi SMDiagnostic Err; 30bb383ae6SHiroshi Yamauchi std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C); 31bb383ae6SHiroshi Yamauchi if (!Mod) 32bb383ae6SHiroshi Yamauchi Err.print("UtilsTests", errs()); 33bb383ae6SHiroshi Yamauchi return Mod; 34bb383ae6SHiroshi Yamauchi } 35bb383ae6SHiroshi Yamauchi 365d3f2967SMingming Liu // Returns a constant representing the vtable's address point specified by the 375d3f2967SMingming Liu // offset. 385d3f2967SMingming Liu static Constant *getVTableAddressPointOffset(GlobalVariable *VTable, 395d3f2967SMingming Liu uint32_t AddressPointOffset) { 405d3f2967SMingming Liu Module &M = *VTable->getParent(); 415d3f2967SMingming Liu LLVMContext &Context = M.getContext(); 425d3f2967SMingming Liu assert(AddressPointOffset < 435d3f2967SMingming Liu M.getDataLayout().getTypeAllocSize(VTable->getValueType()) && 445d3f2967SMingming Liu "Out-of-bound access"); 455d3f2967SMingming Liu 465d3f2967SMingming Liu return ConstantExpr::getInBoundsGetElementPtr( 475d3f2967SMingming Liu Type::getInt8Ty(Context), VTable, 485d3f2967SMingming Liu llvm::ConstantInt::get(Type::getInt32Ty(Context), AddressPointOffset)); 495d3f2967SMingming Liu } 505d3f2967SMingming Liu 51bb383ae6SHiroshi Yamauchi TEST(CallPromotionUtilsTest, TryPromoteCall) { 52bb383ae6SHiroshi Yamauchi LLVMContext C; 53bb383ae6SHiroshi Yamauchi std::unique_ptr<Module> M = parseIR(C, 54bb383ae6SHiroshi Yamauchi R"IR( 55bb383ae6SHiroshi Yamauchi %class.Impl = type <{ %class.Interface, i32, [4 x i8] }> 56bb383ae6SHiroshi Yamauchi %class.Interface = type { i32 (...)** } 57bb383ae6SHiroshi Yamauchi 58bb383ae6SHiroshi Yamauchi @_ZTV4Impl = constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (void (%class.Impl*)* @_ZN4Impl3RunEv to i8*)] } 59bb383ae6SHiroshi Yamauchi 60bb383ae6SHiroshi Yamauchi define void @f() { 61bb383ae6SHiroshi Yamauchi entry: 62bb383ae6SHiroshi Yamauchi %o = alloca %class.Impl 63bb383ae6SHiroshi Yamauchi %base = getelementptr %class.Impl, %class.Impl* %o, i64 0, i32 0, i32 0 6420b15e64SNikita Popov store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV4Impl, i64 0, i32 0, i64 2) to i32 (...)**), i32 (...)*** %base 65bb383ae6SHiroshi Yamauchi %f = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 1 66bb383ae6SHiroshi Yamauchi store i32 3, i32* %f 67bb383ae6SHiroshi Yamauchi %base.i = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 0 68bb383ae6SHiroshi Yamauchi %c = bitcast %class.Interface* %base.i to void (%class.Interface*)*** 69bb383ae6SHiroshi Yamauchi %vtable.i = load void (%class.Interface*)**, void (%class.Interface*)*** %c 70bb383ae6SHiroshi Yamauchi %fp = load void (%class.Interface*)*, void (%class.Interface*)** %vtable.i 71bb383ae6SHiroshi Yamauchi call void %fp(%class.Interface* nonnull %base.i) 72bb383ae6SHiroshi Yamauchi ret void 73bb383ae6SHiroshi Yamauchi } 74bb383ae6SHiroshi Yamauchi 75bb383ae6SHiroshi Yamauchi declare void @_ZN4Impl3RunEv(%class.Impl* %this) 76bb383ae6SHiroshi Yamauchi )IR"); 77bb383ae6SHiroshi Yamauchi 78bb383ae6SHiroshi Yamauchi auto *GV = M->getNamedValue("f"); 79bb383ae6SHiroshi Yamauchi ASSERT_TRUE(GV); 80bb383ae6SHiroshi Yamauchi auto *F = dyn_cast<Function>(GV); 81bb383ae6SHiroshi Yamauchi ASSERT_TRUE(F); 82bb383ae6SHiroshi Yamauchi Instruction *Inst = &F->front().front(); 83bb383ae6SHiroshi Yamauchi auto *AI = dyn_cast<AllocaInst>(Inst); 84bb383ae6SHiroshi Yamauchi ASSERT_TRUE(AI); 85bb383ae6SHiroshi Yamauchi Inst = &*++F->front().rbegin(); 86bb383ae6SHiroshi Yamauchi auto *CI = dyn_cast<CallInst>(Inst); 87bb383ae6SHiroshi Yamauchi ASSERT_TRUE(CI); 88d2f1cd5dSMircea Trofin ASSERT_FALSE(CI->getCalledFunction()); 89d2f1cd5dSMircea Trofin bool IsPromoted = tryPromoteCall(*CI); 90bb383ae6SHiroshi Yamauchi EXPECT_TRUE(IsPromoted); 91bb383ae6SHiroshi Yamauchi GV = M->getNamedValue("_ZN4Impl3RunEv"); 92bb383ae6SHiroshi Yamauchi ASSERT_TRUE(GV); 93bb383ae6SHiroshi Yamauchi auto *F1 = dyn_cast<Function>(GV); 94d2f1cd5dSMircea Trofin EXPECT_EQ(F1, CI->getCalledFunction()); 95bb383ae6SHiroshi Yamauchi } 96bb383ae6SHiroshi Yamauchi 97bb383ae6SHiroshi Yamauchi TEST(CallPromotionUtilsTest, TryPromoteCall_NoFPLoad) { 98bb383ae6SHiroshi Yamauchi LLVMContext C; 99bb383ae6SHiroshi Yamauchi std::unique_ptr<Module> M = parseIR(C, 100bb383ae6SHiroshi Yamauchi R"IR( 101bb383ae6SHiroshi Yamauchi %class.Impl = type <{ %class.Interface, i32, [4 x i8] }> 102bb383ae6SHiroshi Yamauchi %class.Interface = type { i32 (...)** } 103bb383ae6SHiroshi Yamauchi 104bb383ae6SHiroshi Yamauchi define void @f(void (%class.Interface*)* %fp, %class.Interface* nonnull %base.i) { 105bb383ae6SHiroshi Yamauchi entry: 106bb383ae6SHiroshi Yamauchi call void %fp(%class.Interface* nonnull %base.i) 107bb383ae6SHiroshi Yamauchi ret void 108bb383ae6SHiroshi Yamauchi } 109bb383ae6SHiroshi Yamauchi )IR"); 110bb383ae6SHiroshi Yamauchi 111bb383ae6SHiroshi Yamauchi auto *GV = M->getNamedValue("f"); 112bb383ae6SHiroshi Yamauchi ASSERT_TRUE(GV); 113bb383ae6SHiroshi Yamauchi auto *F = dyn_cast<Function>(GV); 114bb383ae6SHiroshi Yamauchi ASSERT_TRUE(F); 115bb383ae6SHiroshi Yamauchi Instruction *Inst = &F->front().front(); 116bb383ae6SHiroshi Yamauchi auto *CI = dyn_cast<CallInst>(Inst); 117bb383ae6SHiroshi Yamauchi ASSERT_TRUE(CI); 118d2f1cd5dSMircea Trofin ASSERT_FALSE(CI->getCalledFunction()); 119d2f1cd5dSMircea Trofin bool IsPromoted = tryPromoteCall(*CI); 120bb383ae6SHiroshi Yamauchi EXPECT_FALSE(IsPromoted); 121bb383ae6SHiroshi Yamauchi } 122bb383ae6SHiroshi Yamauchi 123bb383ae6SHiroshi Yamauchi TEST(CallPromotionUtilsTest, TryPromoteCall_NoVTablePtrLoad) { 124bb383ae6SHiroshi Yamauchi LLVMContext C; 125bb383ae6SHiroshi Yamauchi std::unique_ptr<Module> M = parseIR(C, 126bb383ae6SHiroshi Yamauchi R"IR( 127bb383ae6SHiroshi Yamauchi %class.Impl = type <{ %class.Interface, i32, [4 x i8] }> 128bb383ae6SHiroshi Yamauchi %class.Interface = type { i32 (...)** } 129bb383ae6SHiroshi Yamauchi 130bb383ae6SHiroshi Yamauchi define void @f(void (%class.Interface*)** %vtable.i, %class.Interface* nonnull %base.i) { 131bb383ae6SHiroshi Yamauchi entry: 132bb383ae6SHiroshi Yamauchi %fp = load void (%class.Interface*)*, void (%class.Interface*)** %vtable.i 133bb383ae6SHiroshi Yamauchi call void %fp(%class.Interface* nonnull %base.i) 134bb383ae6SHiroshi Yamauchi ret void 135bb383ae6SHiroshi Yamauchi } 136bb383ae6SHiroshi Yamauchi )IR"); 137bb383ae6SHiroshi Yamauchi 138bb383ae6SHiroshi Yamauchi auto *GV = M->getNamedValue("f"); 139bb383ae6SHiroshi Yamauchi ASSERT_TRUE(GV); 140bb383ae6SHiroshi Yamauchi auto *F = dyn_cast<Function>(GV); 141bb383ae6SHiroshi Yamauchi ASSERT_TRUE(F); 142bb383ae6SHiroshi Yamauchi Instruction *Inst = &*++F->front().rbegin(); 143bb383ae6SHiroshi Yamauchi auto *CI = dyn_cast<CallInst>(Inst); 144bb383ae6SHiroshi Yamauchi ASSERT_TRUE(CI); 145d2f1cd5dSMircea Trofin ASSERT_FALSE(CI->getCalledFunction()); 146d2f1cd5dSMircea Trofin bool IsPromoted = tryPromoteCall(*CI); 147bb383ae6SHiroshi Yamauchi EXPECT_FALSE(IsPromoted); 148bb383ae6SHiroshi Yamauchi } 149bb383ae6SHiroshi Yamauchi 150bb383ae6SHiroshi Yamauchi TEST(CallPromotionUtilsTest, TryPromoteCall_NoVTableInitFound) { 151bb383ae6SHiroshi Yamauchi LLVMContext C; 152bb383ae6SHiroshi Yamauchi std::unique_ptr<Module> M = parseIR(C, 153bb383ae6SHiroshi Yamauchi R"IR( 154bb383ae6SHiroshi Yamauchi %class.Impl = type <{ %class.Interface, i32, [4 x i8] }> 155bb383ae6SHiroshi Yamauchi %class.Interface = type { i32 (...)** } 156bb383ae6SHiroshi Yamauchi 157bb383ae6SHiroshi Yamauchi define void @f() { 158bb383ae6SHiroshi Yamauchi entry: 159bb383ae6SHiroshi Yamauchi %o = alloca %class.Impl 160bb383ae6SHiroshi Yamauchi %f = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 1 161bb383ae6SHiroshi Yamauchi store i32 3, i32* %f 162bb383ae6SHiroshi Yamauchi %base.i = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 0 163bb383ae6SHiroshi Yamauchi %c = bitcast %class.Interface* %base.i to void (%class.Interface*)*** 164bb383ae6SHiroshi Yamauchi %vtable.i = load void (%class.Interface*)**, void (%class.Interface*)*** %c 165bb383ae6SHiroshi Yamauchi %fp = load void (%class.Interface*)*, void (%class.Interface*)** %vtable.i 166bb383ae6SHiroshi Yamauchi call void %fp(%class.Interface* nonnull %base.i) 167bb383ae6SHiroshi Yamauchi ret void 168bb383ae6SHiroshi Yamauchi } 169bb383ae6SHiroshi Yamauchi 170bb383ae6SHiroshi Yamauchi declare void @_ZN4Impl3RunEv(%class.Impl* %this) 171bb383ae6SHiroshi Yamauchi )IR"); 172bb383ae6SHiroshi Yamauchi 173bb383ae6SHiroshi Yamauchi auto *GV = M->getNamedValue("f"); 174bb383ae6SHiroshi Yamauchi ASSERT_TRUE(GV); 175bb383ae6SHiroshi Yamauchi auto *F = dyn_cast<Function>(GV); 176bb383ae6SHiroshi Yamauchi ASSERT_TRUE(F); 177bb383ae6SHiroshi Yamauchi Instruction *Inst = &*++F->front().rbegin(); 178bb383ae6SHiroshi Yamauchi auto *CI = dyn_cast<CallInst>(Inst); 179bb383ae6SHiroshi Yamauchi ASSERT_TRUE(CI); 180d2f1cd5dSMircea Trofin ASSERT_FALSE(CI->getCalledFunction()); 181d2f1cd5dSMircea Trofin bool IsPromoted = tryPromoteCall(*CI); 182bb383ae6SHiroshi Yamauchi EXPECT_FALSE(IsPromoted); 183bb383ae6SHiroshi Yamauchi } 184bb383ae6SHiroshi Yamauchi 185bb383ae6SHiroshi Yamauchi TEST(CallPromotionUtilsTest, TryPromoteCall_EmptyVTable) { 186bb383ae6SHiroshi Yamauchi LLVMContext C; 187bb383ae6SHiroshi Yamauchi std::unique_ptr<Module> M = parseIR(C, 188bb383ae6SHiroshi Yamauchi R"IR( 189bb383ae6SHiroshi Yamauchi %class.Impl = type <{ %class.Interface, i32, [4 x i8] }> 190bb383ae6SHiroshi Yamauchi %class.Interface = type { i32 (...)** } 191bb383ae6SHiroshi Yamauchi 192bb383ae6SHiroshi Yamauchi @_ZTV4Impl = external global { [3 x i8*] } 193bb383ae6SHiroshi Yamauchi 194bb383ae6SHiroshi Yamauchi define void @f() { 195bb383ae6SHiroshi Yamauchi entry: 196bb383ae6SHiroshi Yamauchi %o = alloca %class.Impl 197bb383ae6SHiroshi Yamauchi %base = getelementptr %class.Impl, %class.Impl* %o, i64 0, i32 0, i32 0 19820b15e64SNikita Popov store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV4Impl, i64 0, i32 0, i64 2) to i32 (...)**), i32 (...)*** %base 199bb383ae6SHiroshi Yamauchi %f = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 1 200bb383ae6SHiroshi Yamauchi store i32 3, i32* %f 201bb383ae6SHiroshi Yamauchi %base.i = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 0 202bb383ae6SHiroshi Yamauchi %c = bitcast %class.Interface* %base.i to void (%class.Interface*)*** 203bb383ae6SHiroshi Yamauchi %vtable.i = load void (%class.Interface*)**, void (%class.Interface*)*** %c 204bb383ae6SHiroshi Yamauchi %fp = load void (%class.Interface*)*, void (%class.Interface*)** %vtable.i 205bb383ae6SHiroshi Yamauchi call void %fp(%class.Interface* nonnull %base.i) 206bb383ae6SHiroshi Yamauchi ret void 207bb383ae6SHiroshi Yamauchi } 208bb383ae6SHiroshi Yamauchi 209bb383ae6SHiroshi Yamauchi declare void @_ZN4Impl3RunEv(%class.Impl* %this) 210bb383ae6SHiroshi Yamauchi )IR"); 211bb383ae6SHiroshi Yamauchi 212bb383ae6SHiroshi Yamauchi auto *GV = M->getNamedValue("f"); 213bb383ae6SHiroshi Yamauchi ASSERT_TRUE(GV); 214bb383ae6SHiroshi Yamauchi auto *F = dyn_cast<Function>(GV); 215bb383ae6SHiroshi Yamauchi ASSERT_TRUE(F); 216bb383ae6SHiroshi Yamauchi Instruction *Inst = &F->front().front(); 217bb383ae6SHiroshi Yamauchi auto *AI = dyn_cast<AllocaInst>(Inst); 218bb383ae6SHiroshi Yamauchi ASSERT_TRUE(AI); 219bb383ae6SHiroshi Yamauchi Inst = &*++F->front().rbegin(); 220bb383ae6SHiroshi Yamauchi auto *CI = dyn_cast<CallInst>(Inst); 221bb383ae6SHiroshi Yamauchi ASSERT_TRUE(CI); 222d2f1cd5dSMircea Trofin ASSERT_FALSE(CI->getCalledFunction()); 223d2f1cd5dSMircea Trofin bool IsPromoted = tryPromoteCall(*CI); 224bb383ae6SHiroshi Yamauchi EXPECT_FALSE(IsPromoted); 225bb383ae6SHiroshi Yamauchi } 226bb383ae6SHiroshi Yamauchi 227bb383ae6SHiroshi Yamauchi TEST(CallPromotionUtilsTest, TryPromoteCall_NullFP) { 228bb383ae6SHiroshi Yamauchi LLVMContext C; 229bb383ae6SHiroshi Yamauchi std::unique_ptr<Module> M = parseIR(C, 230bb383ae6SHiroshi Yamauchi R"IR( 231bb383ae6SHiroshi Yamauchi %class.Impl = type <{ %class.Interface, i32, [4 x i8] }> 232bb383ae6SHiroshi Yamauchi %class.Interface = type { i32 (...)** } 233bb383ae6SHiroshi Yamauchi 234bb383ae6SHiroshi Yamauchi @_ZTV4Impl = constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* null] } 235bb383ae6SHiroshi Yamauchi 236bb383ae6SHiroshi Yamauchi define void @f() { 237bb383ae6SHiroshi Yamauchi entry: 238bb383ae6SHiroshi Yamauchi %o = alloca %class.Impl 239bb383ae6SHiroshi Yamauchi %base = getelementptr %class.Impl, %class.Impl* %o, i64 0, i32 0, i32 0 24020b15e64SNikita Popov store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV4Impl, i64 0, i32 0, i64 2) to i32 (...)**), i32 (...)*** %base 241bb383ae6SHiroshi Yamauchi %f = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 1 242bb383ae6SHiroshi Yamauchi store i32 3, i32* %f 243bb383ae6SHiroshi Yamauchi %base.i = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 0 244bb383ae6SHiroshi Yamauchi %c = bitcast %class.Interface* %base.i to void (%class.Interface*)*** 245bb383ae6SHiroshi Yamauchi %vtable.i = load void (%class.Interface*)**, void (%class.Interface*)*** %c 246bb383ae6SHiroshi Yamauchi %fp = load void (%class.Interface*)*, void (%class.Interface*)** %vtable.i 247bb383ae6SHiroshi Yamauchi call void %fp(%class.Interface* nonnull %base.i) 248bb383ae6SHiroshi Yamauchi ret void 249bb383ae6SHiroshi Yamauchi } 250bb383ae6SHiroshi Yamauchi 251bb383ae6SHiroshi Yamauchi declare void @_ZN4Impl3RunEv(%class.Impl* %this) 252bb383ae6SHiroshi Yamauchi )IR"); 253bb383ae6SHiroshi Yamauchi 254bb383ae6SHiroshi Yamauchi auto *GV = M->getNamedValue("f"); 255bb383ae6SHiroshi Yamauchi ASSERT_TRUE(GV); 256bb383ae6SHiroshi Yamauchi auto *F = dyn_cast<Function>(GV); 257bb383ae6SHiroshi Yamauchi ASSERT_TRUE(F); 258bb383ae6SHiroshi Yamauchi Instruction *Inst = &F->front().front(); 259bb383ae6SHiroshi Yamauchi auto *AI = dyn_cast<AllocaInst>(Inst); 260bb383ae6SHiroshi Yamauchi ASSERT_TRUE(AI); 261bb383ae6SHiroshi Yamauchi Inst = &*++F->front().rbegin(); 262bb383ae6SHiroshi Yamauchi auto *CI = dyn_cast<CallInst>(Inst); 263bb383ae6SHiroshi Yamauchi ASSERT_TRUE(CI); 264d2f1cd5dSMircea Trofin ASSERT_FALSE(CI->getCalledFunction()); 265d2f1cd5dSMircea Trofin bool IsPromoted = tryPromoteCall(*CI); 266bb383ae6SHiroshi Yamauchi EXPECT_FALSE(IsPromoted); 267bb383ae6SHiroshi Yamauchi } 268bb383ae6SHiroshi Yamauchi 269bb383ae6SHiroshi Yamauchi // Based on clang/test/CodeGenCXX/member-function-pointer-calls.cpp 270bb383ae6SHiroshi Yamauchi TEST(CallPromotionUtilsTest, TryPromoteCall_MemberFunctionCalls) { 271bb383ae6SHiroshi Yamauchi LLVMContext C; 272bb383ae6SHiroshi Yamauchi std::unique_ptr<Module> M = parseIR(C, 273bb383ae6SHiroshi Yamauchi R"IR( 274bb383ae6SHiroshi Yamauchi %struct.A = type { i32 (...)** } 275bb383ae6SHiroshi Yamauchi 276bb383ae6SHiroshi Yamauchi @_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 8 277bb383ae6SHiroshi Yamauchi 278bb383ae6SHiroshi Yamauchi define i32 @_Z2g1v() { 279bb383ae6SHiroshi Yamauchi entry: 280bb383ae6SHiroshi Yamauchi %a = alloca %struct.A, align 8 281bb383ae6SHiroshi Yamauchi %0 = bitcast %struct.A* %a to i8* 282bb383ae6SHiroshi Yamauchi %1 = getelementptr %struct.A, %struct.A* %a, i64 0, i32 0 28320b15e64SNikita Popov store i32 (...)** bitcast (i8** getelementptr inbounds ({ [4 x i8*] }, { [4 x i8*] }* @_ZTV1A, i64 0, i32 0, i64 2) to i32 (...)**), i32 (...)*** %1, align 8 284bb383ae6SHiroshi Yamauchi %2 = bitcast %struct.A* %a to i8* 285bb383ae6SHiroshi Yamauchi %3 = bitcast i8* %2 to i8** 286bb383ae6SHiroshi Yamauchi %vtable.i = load i8*, i8** %3, align 8 287bb383ae6SHiroshi Yamauchi %4 = bitcast i8* %vtable.i to i32 (%struct.A*)** 288bb383ae6SHiroshi Yamauchi %memptr.virtualfn.i = load i32 (%struct.A*)*, i32 (%struct.A*)** %4, align 8 289bb383ae6SHiroshi Yamauchi %call.i = call i32 %memptr.virtualfn.i(%struct.A* %a) 290bb383ae6SHiroshi Yamauchi ret i32 %call.i 291bb383ae6SHiroshi Yamauchi } 292bb383ae6SHiroshi Yamauchi 293bb383ae6SHiroshi Yamauchi define i32 @_Z2g2v() { 294bb383ae6SHiroshi Yamauchi entry: 295bb383ae6SHiroshi Yamauchi %a = alloca %struct.A, align 8 296bb383ae6SHiroshi Yamauchi %0 = bitcast %struct.A* %a to i8* 297bb383ae6SHiroshi Yamauchi %1 = getelementptr %struct.A, %struct.A* %a, i64 0, i32 0 29820b15e64SNikita Popov store i32 (...)** bitcast (i8** getelementptr inbounds ({ [4 x i8*] }, { [4 x i8*] }* @_ZTV1A, i64 0, i32 0, i64 2) to i32 (...)**), i32 (...)*** %1, align 8 299bb383ae6SHiroshi Yamauchi %2 = bitcast %struct.A* %a to i8* 300bb383ae6SHiroshi Yamauchi %3 = bitcast i8* %2 to i8** 301bb383ae6SHiroshi Yamauchi %vtable.i = load i8*, i8** %3, align 8 302bb383ae6SHiroshi Yamauchi %4 = getelementptr i8, i8* %vtable.i, i64 8 303bb383ae6SHiroshi Yamauchi %5 = bitcast i8* %4 to i32 (%struct.A*)** 304bb383ae6SHiroshi Yamauchi %memptr.virtualfn.i = load i32 (%struct.A*)*, i32 (%struct.A*)** %5, align 8 305bb383ae6SHiroshi Yamauchi %call.i = call i32 %memptr.virtualfn.i(%struct.A* %a) 306bb383ae6SHiroshi Yamauchi ret i32 %call.i 307bb383ae6SHiroshi Yamauchi } 308bb383ae6SHiroshi Yamauchi 309bb383ae6SHiroshi Yamauchi declare i32 @_ZN1A3vf1Ev(%struct.A* %this) 310bb383ae6SHiroshi Yamauchi declare i32 @_ZN1A3vf2Ev(%struct.A* %this) 311bb383ae6SHiroshi Yamauchi )IR"); 312bb383ae6SHiroshi Yamauchi 313bb383ae6SHiroshi Yamauchi auto *GV = M->getNamedValue("_Z2g1v"); 314bb383ae6SHiroshi Yamauchi ASSERT_TRUE(GV); 315bb383ae6SHiroshi Yamauchi auto *F = dyn_cast<Function>(GV); 316bb383ae6SHiroshi Yamauchi ASSERT_TRUE(F); 317bb383ae6SHiroshi Yamauchi Instruction *Inst = &F->front().front(); 318bb383ae6SHiroshi Yamauchi auto *AI = dyn_cast<AllocaInst>(Inst); 319bb383ae6SHiroshi Yamauchi ASSERT_TRUE(AI); 320bb383ae6SHiroshi Yamauchi Inst = &*++F->front().rbegin(); 321bb383ae6SHiroshi Yamauchi auto *CI = dyn_cast<CallInst>(Inst); 322bb383ae6SHiroshi Yamauchi ASSERT_TRUE(CI); 323d2f1cd5dSMircea Trofin ASSERT_FALSE(CI->getCalledFunction()); 324d2f1cd5dSMircea Trofin bool IsPromoted1 = tryPromoteCall(*CI); 325bb383ae6SHiroshi Yamauchi EXPECT_TRUE(IsPromoted1); 326bb383ae6SHiroshi Yamauchi GV = M->getNamedValue("_ZN1A3vf1Ev"); 327bb383ae6SHiroshi Yamauchi ASSERT_TRUE(GV); 328bb383ae6SHiroshi Yamauchi F = dyn_cast<Function>(GV); 329d2f1cd5dSMircea Trofin EXPECT_EQ(F, CI->getCalledFunction()); 330bb383ae6SHiroshi Yamauchi 331bb383ae6SHiroshi Yamauchi GV = M->getNamedValue("_Z2g2v"); 332bb383ae6SHiroshi Yamauchi ASSERT_TRUE(GV); 333bb383ae6SHiroshi Yamauchi F = dyn_cast<Function>(GV); 334bb383ae6SHiroshi Yamauchi ASSERT_TRUE(F); 335bb383ae6SHiroshi Yamauchi Inst = &F->front().front(); 336bb383ae6SHiroshi Yamauchi AI = dyn_cast<AllocaInst>(Inst); 337bb383ae6SHiroshi Yamauchi ASSERT_TRUE(AI); 338bb383ae6SHiroshi Yamauchi Inst = &*++F->front().rbegin(); 339bb383ae6SHiroshi Yamauchi CI = dyn_cast<CallInst>(Inst); 340bb383ae6SHiroshi Yamauchi ASSERT_TRUE(CI); 341d2f1cd5dSMircea Trofin ASSERT_FALSE(CI->getCalledFunction()); 342d2f1cd5dSMircea Trofin bool IsPromoted2 = tryPromoteCall(*CI); 343bb383ae6SHiroshi Yamauchi EXPECT_TRUE(IsPromoted2); 344bb383ae6SHiroshi Yamauchi GV = M->getNamedValue("_ZN1A3vf2Ev"); 345bb383ae6SHiroshi Yamauchi ASSERT_TRUE(GV); 346bb383ae6SHiroshi Yamauchi F = dyn_cast<Function>(GV); 347d2f1cd5dSMircea Trofin EXPECT_EQ(F, CI->getCalledFunction()); 348bb383ae6SHiroshi Yamauchi } 34941e06ae7SHiroshi Yamauchi 35041e06ae7SHiroshi Yamauchi // Check that it isn't crashing due to missing promotion legality. 35141e06ae7SHiroshi Yamauchi TEST(CallPromotionUtilsTest, TryPromoteCall_Legality) { 35241e06ae7SHiroshi Yamauchi LLVMContext C; 35341e06ae7SHiroshi Yamauchi std::unique_ptr<Module> M = parseIR(C, 35441e06ae7SHiroshi Yamauchi R"IR( 35541e06ae7SHiroshi Yamauchi %struct1 = type <{ i32, i64 }> 35641e06ae7SHiroshi Yamauchi %struct2 = type <{ i32, i64 }> 35741e06ae7SHiroshi Yamauchi 35841e06ae7SHiroshi Yamauchi %class.Impl = type <{ %class.Interface, i32, [4 x i8] }> 35941e06ae7SHiroshi Yamauchi %class.Interface = type { i32 (...)** } 36041e06ae7SHiroshi Yamauchi 36141e06ae7SHiroshi Yamauchi @_ZTV4Impl = constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (%struct2 (%class.Impl*)* @_ZN4Impl3RunEv to i8*)] } 36241e06ae7SHiroshi Yamauchi 36341e06ae7SHiroshi Yamauchi define %struct1 @f() { 36441e06ae7SHiroshi Yamauchi entry: 36541e06ae7SHiroshi Yamauchi %o = alloca %class.Impl 36641e06ae7SHiroshi Yamauchi %base = getelementptr %class.Impl, %class.Impl* %o, i64 0, i32 0, i32 0 36720b15e64SNikita Popov store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV4Impl, i64 0, i32 0, i64 2) to i32 (...)**), i32 (...)*** %base 36841e06ae7SHiroshi Yamauchi %f = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 1 36941e06ae7SHiroshi Yamauchi store i32 3, i32* %f 37041e06ae7SHiroshi Yamauchi %base.i = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 0 37141e06ae7SHiroshi Yamauchi %c = bitcast %class.Interface* %base.i to %struct1 (%class.Interface*)*** 37241e06ae7SHiroshi Yamauchi %vtable.i = load %struct1 (%class.Interface*)**, %struct1 (%class.Interface*)*** %c 37341e06ae7SHiroshi Yamauchi %fp = load %struct1 (%class.Interface*)*, %struct1 (%class.Interface*)** %vtable.i 37441e06ae7SHiroshi Yamauchi %rv = call %struct1 %fp(%class.Interface* nonnull %base.i) 37541e06ae7SHiroshi Yamauchi ret %struct1 %rv 37641e06ae7SHiroshi Yamauchi } 37741e06ae7SHiroshi Yamauchi 37841e06ae7SHiroshi Yamauchi declare %struct2 @_ZN4Impl3RunEv(%class.Impl* %this) 37941e06ae7SHiroshi Yamauchi )IR"); 38041e06ae7SHiroshi Yamauchi 38141e06ae7SHiroshi Yamauchi auto *GV = M->getNamedValue("f"); 38241e06ae7SHiroshi Yamauchi ASSERT_TRUE(GV); 38341e06ae7SHiroshi Yamauchi auto *F = dyn_cast<Function>(GV); 38441e06ae7SHiroshi Yamauchi ASSERT_TRUE(F); 38541e06ae7SHiroshi Yamauchi Instruction *Inst = &F->front().front(); 38641e06ae7SHiroshi Yamauchi auto *AI = dyn_cast<AllocaInst>(Inst); 38741e06ae7SHiroshi Yamauchi ASSERT_TRUE(AI); 38841e06ae7SHiroshi Yamauchi Inst = &*++F->front().rbegin(); 38941e06ae7SHiroshi Yamauchi auto *CI = dyn_cast<CallInst>(Inst); 39041e06ae7SHiroshi Yamauchi ASSERT_TRUE(CI); 391d2f1cd5dSMircea Trofin ASSERT_FALSE(CI->getCalledFunction()); 392d2f1cd5dSMircea Trofin bool IsPromoted = tryPromoteCall(*CI); 39341e06ae7SHiroshi Yamauchi EXPECT_FALSE(IsPromoted); 39441e06ae7SHiroshi Yamauchi } 3955d3f2967SMingming Liu 3965d3f2967SMingming Liu TEST(CallPromotionUtilsTest, promoteCallWithVTableCmp) { 3975d3f2967SMingming Liu LLVMContext C; 3985d3f2967SMingming Liu std::unique_ptr<Module> M = parseIR(C, 3995d3f2967SMingming Liu R"IR( 4005d3f2967SMingming Liu target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" 4015d3f2967SMingming Liu target triple = "x86_64-unknown-linux-gnu" 4025d3f2967SMingming Liu 4035d3f2967SMingming Liu @_ZTV5Base1 = constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr null, ptr @_ZN5Base15func0Ev, ptr @_ZN5Base15func1Ev] }, !type !0 4045d3f2967SMingming Liu @_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 !2 4055d3f2967SMingming Liu @_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 !6 4065d3f2967SMingming Liu 4075d3f2967SMingming Liu define i32 @testfunc(ptr %d) { 4085d3f2967SMingming Liu entry: 4095d3f2967SMingming Liu %vtable = load ptr, ptr %d, !prof !7 4105d3f2967SMingming Liu %vfn = getelementptr inbounds ptr, ptr %vtable, i64 1 4115d3f2967SMingming Liu %0 = load ptr, ptr %vfn 4125d3f2967SMingming Liu %call = tail call i32 %0(ptr %d), !prof !8 4135d3f2967SMingming Liu ret i32 %call 4145d3f2967SMingming Liu } 4155d3f2967SMingming Liu 4165d3f2967SMingming Liu define i32 @_ZN5Base15func1Ev(ptr %this) { 4175d3f2967SMingming Liu entry: 4185d3f2967SMingming Liu ret i32 2 4195d3f2967SMingming Liu } 4205d3f2967SMingming Liu 4215d3f2967SMingming Liu declare i32 @_ZN5Base25func2Ev(ptr) 4225d3f2967SMingming Liu declare i32 @_ZN5Base15func0Ev(ptr) 4235d3f2967SMingming Liu declare void @_ZN5Base35func3Ev(ptr) 4245d3f2967SMingming Liu 4255d3f2967SMingming Liu !0 = !{i64 16, !"_ZTS5Base1"} 4265d3f2967SMingming Liu !1 = !{i64 48, !"_ZTS5Base2"} 4275d3f2967SMingming Liu !2 = !{i64 16, !"_ZTS8Derived1"} 4285d3f2967SMingming Liu !3 = !{i64 64, !"_ZTS5Base1"} 4295d3f2967SMingming Liu !4 = !{i64 40, !"_ZTS5Base2"} 4305d3f2967SMingming Liu !5 = !{i64 16, !"_ZTS5Base3"} 4315d3f2967SMingming Liu !6 = !{i64 16, !"_ZTS8Derived2"} 4325d3f2967SMingming Liu !7 = !{!"VP", i32 2, i64 1600, i64 -9064381665493407289, i64 800, i64 5035968517245772950, i64 500, i64 3215870116411581797, i64 300} 4335d3f2967SMingming Liu !8 = !{!"VP", i32 0, i64 1600, i64 6804820478065511155, i64 1600})IR"); 4345d3f2967SMingming Liu 4355d3f2967SMingming Liu Function *F = M->getFunction("testfunc"); 4365d3f2967SMingming Liu CallInst *CI = dyn_cast<CallInst>(&*std::next(F->front().rbegin())); 4375d3f2967SMingming Liu ASSERT_TRUE(CI && CI->isIndirectCall()); 4385d3f2967SMingming Liu 4395d3f2967SMingming Liu // Create the constant and the branch weights 4405d3f2967SMingming Liu SmallVector<Constant *, 3> VTableAddressPoints; 4415d3f2967SMingming Liu 4425d3f2967SMingming Liu for (auto &[VTableName, AddressPointOffset] : {std::pair{"_ZTV5Base1", 16}, 4435d3f2967SMingming Liu {"_ZTV8Derived1", 16}, 4445d3f2967SMingming Liu {"_ZTV8Derived2", 64}}) 4455d3f2967SMingming Liu VTableAddressPoints.push_back(getVTableAddressPointOffset( 4465d3f2967SMingming Liu M->getGlobalVariable(VTableName), AddressPointOffset)); 4475d3f2967SMingming Liu 4485d3f2967SMingming Liu MDBuilder MDB(C); 4495d3f2967SMingming Liu MDNode *BranchWeights = MDB.createBranchWeights(1600, 0); 4505d3f2967SMingming Liu 4515d3f2967SMingming Liu size_t OrigEntryBBSize = F->front().size(); 4525d3f2967SMingming Liu 4535d3f2967SMingming Liu LoadInst *VPtr = dyn_cast<LoadInst>(&*F->front().begin()); 4545d3f2967SMingming Liu 4555d3f2967SMingming Liu Function *Callee = M->getFunction("_ZN5Base15func1Ev"); 4565d3f2967SMingming Liu // Tests that promoted direct call is returned. 4575d3f2967SMingming Liu CallBase &DirectCB = promoteCallWithVTableCmp( 4585d3f2967SMingming Liu *CI, VPtr, Callee, VTableAddressPoints, BranchWeights); 4595d3f2967SMingming Liu EXPECT_EQ(DirectCB.getCalledOperand(), Callee); 4605d3f2967SMingming Liu 4615d3f2967SMingming Liu // Promotion inserts 3 icmp instructions and 2 or instructions, and removes 4625d3f2967SMingming Liu // 1 call instruction from the entry block. 4635d3f2967SMingming Liu EXPECT_EQ(F->front().size(), OrigEntryBBSize + 4); 4645d3f2967SMingming Liu } 46573c3b733SMircea Trofin 46673c3b733SMircea Trofin TEST(CallPromotionUtilsTest, PromoteWithIcmpAndCtxProf) { 46773c3b733SMircea Trofin LLVMContext C; 46873c3b733SMircea Trofin std::unique_ptr<Module> M = parseIR(C, 46973c3b733SMircea Trofin R"IR( 47073c3b733SMircea Trofin define i32 @testfunc1(ptr %d) !guid !0 { 47173c3b733SMircea Trofin call void @llvm.instrprof.increment(ptr @testfunc1, i64 0, i32 1, i32 0) 47273c3b733SMircea Trofin call void @llvm.instrprof.callsite(ptr @testfunc1, i64 0, i32 1, i32 0, ptr %d) 47373c3b733SMircea Trofin %call = call i32 %d() 47473c3b733SMircea Trofin ret i32 %call 47573c3b733SMircea Trofin } 47673c3b733SMircea Trofin 47773c3b733SMircea Trofin define i32 @f1() !guid !1 { 47873c3b733SMircea Trofin call void @llvm.instrprof.increment(ptr @f1, i64 0, i32 1, i32 0) 47973c3b733SMircea Trofin ret i32 2 48073c3b733SMircea Trofin } 48173c3b733SMircea Trofin 48273c3b733SMircea Trofin define i32 @f2() !guid !2 { 48373c3b733SMircea Trofin call void @llvm.instrprof.increment(ptr @f2, i64 0, i32 1, i32 0) 48473c3b733SMircea Trofin call void @llvm.instrprof.callsite(ptr @f2, i64 0, i32 1, i32 0, ptr @f4) 48573c3b733SMircea Trofin %r = call i32 @f4() 48673c3b733SMircea Trofin ret i32 %r 48773c3b733SMircea Trofin } 48873c3b733SMircea Trofin 48973c3b733SMircea Trofin define i32 @testfunc2(ptr %p) !guid !4 { 49073c3b733SMircea Trofin call void @llvm.instrprof.increment(ptr @testfunc2, i64 0, i32 1, i32 0) 49173c3b733SMircea Trofin call void @llvm.instrprof.callsite(ptr @testfunc2, i64 0, i32 1, i32 0, ptr @testfunc1) 49273c3b733SMircea Trofin %r = call i32 @testfunc1(ptr %p) 49373c3b733SMircea Trofin ret i32 %r 49473c3b733SMircea Trofin } 49573c3b733SMircea Trofin 49673c3b733SMircea Trofin declare i32 @f3() 49773c3b733SMircea Trofin 49873c3b733SMircea Trofin define i32 @f4() !guid !3 { 49973c3b733SMircea Trofin ret i32 3 50073c3b733SMircea Trofin } 50173c3b733SMircea Trofin 50273c3b733SMircea Trofin !0 = !{i64 1000} 50373c3b733SMircea Trofin !1 = !{i64 1001} 50473c3b733SMircea Trofin !2 = !{i64 1002} 50573c3b733SMircea Trofin !3 = !{i64 1004} 50673c3b733SMircea Trofin !4 = !{i64 1005} 50773c3b733SMircea Trofin )IR"); 50873c3b733SMircea Trofin 50973c3b733SMircea Trofin const char *Profile = R"json( 51073c3b733SMircea Trofin [ 51173c3b733SMircea Trofin { 51273c3b733SMircea Trofin "Guid": 1000, 51373c3b733SMircea Trofin "Counters": [1], 51473c3b733SMircea Trofin "Callsites": [ 51573c3b733SMircea Trofin [{ "Guid": 1001, 51673c3b733SMircea Trofin "Counters": [10]}, 51773c3b733SMircea Trofin { "Guid": 1002, 51873c3b733SMircea Trofin "Counters": [11], 51973c3b733SMircea Trofin "Callsites": [[{"Guid": 1004, "Counters":[13]}]] 52073c3b733SMircea Trofin }, 52173c3b733SMircea Trofin { "Guid": 1003, 52273c3b733SMircea Trofin "Counters": [12] 52373c3b733SMircea Trofin }]] 52473c3b733SMircea Trofin }, 52573c3b733SMircea Trofin { 52673c3b733SMircea Trofin "Guid": 1005, 52773c3b733SMircea Trofin "Counters": [2], 52873c3b733SMircea Trofin "Callsites": [ 52973c3b733SMircea Trofin [{ "Guid": 1000, 53073c3b733SMircea Trofin "Counters": [1], 53173c3b733SMircea Trofin "Callsites": [ 53273c3b733SMircea Trofin [{ "Guid": 1001, 53373c3b733SMircea Trofin "Counters": [101]}, 53473c3b733SMircea Trofin { "Guid": 1002, 53573c3b733SMircea Trofin "Counters": [102], 53673c3b733SMircea Trofin "Callsites": [[{"Guid": 1004, "Counters":[104]}]] 53773c3b733SMircea Trofin }, 53873c3b733SMircea Trofin { "Guid": 1003, 53973c3b733SMircea Trofin "Counters": [103] 54073c3b733SMircea Trofin }]]}]]}] 54173c3b733SMircea Trofin )json"; 54273c3b733SMircea Trofin 54373c3b733SMircea Trofin llvm::unittest::TempFile ProfileFile("ctx_profile", "", "", /*Unique=*/true); 54473c3b733SMircea Trofin { 54573c3b733SMircea Trofin std::error_code EC; 54673c3b733SMircea Trofin raw_fd_stream Out(ProfileFile.path(), EC); 54773c3b733SMircea Trofin ASSERT_FALSE(EC); 54873c3b733SMircea Trofin // "False" means no error. 54963293558SMircea Trofin ASSERT_FALSE(llvm::createCtxProfFromYAML(Profile, Out)); 55073c3b733SMircea Trofin } 55173c3b733SMircea Trofin 55273c3b733SMircea Trofin ModuleAnalysisManager MAM; 55373c3b733SMircea Trofin MAM.registerPass([&]() { return CtxProfAnalysis(ProfileFile.path()); }); 55473c3b733SMircea Trofin MAM.registerPass([&]() { return PassInstrumentationAnalysis(); }); 55573c3b733SMircea Trofin auto &CtxProf = MAM.getResult<CtxProfAnalysis>(*M); 55673c3b733SMircea Trofin auto *Caller = M->getFunction("testfunc1"); 55773c3b733SMircea Trofin ASSERT_NE(Caller, nullptr); 55873c3b733SMircea Trofin auto *Callee = M->getFunction("f2"); 55973c3b733SMircea Trofin ASSERT_NE(Callee, nullptr); 56073c3b733SMircea Trofin auto *IndirectCS = [&]() -> CallBase * { 56173c3b733SMircea Trofin for (auto &BB : *Caller) 56273c3b733SMircea Trofin for (auto &I : BB) 56373c3b733SMircea Trofin if (auto *CB = dyn_cast<CallBase>(&I); CB && CB->isIndirectCall()) 56473c3b733SMircea Trofin return CB; 56573c3b733SMircea Trofin return nullptr; 56673c3b733SMircea Trofin }(); 56773c3b733SMircea Trofin ASSERT_NE(IndirectCS, nullptr); 56873c3b733SMircea Trofin promoteCallWithIfThenElse(*IndirectCS, *Callee, CtxProf); 56973c3b733SMircea Trofin 57073c3b733SMircea Trofin std::string Str; 57173c3b733SMircea Trofin raw_string_ostream OS(Str); 57232097666SMircea Trofin CtxProfAnalysisPrinterPass Printer(OS); 57373c3b733SMircea Trofin Printer.run(*M, MAM); 574*b15845c0SMircea Trofin const char *Expected = R"yaml( 575*b15845c0SMircea Trofin - Guid: 1000 576*b15845c0SMircea Trofin Counters: [ 1, 11, 22 ] 577*b15845c0SMircea Trofin Callsites: 578*b15845c0SMircea Trofin - - Guid: 1001 579*b15845c0SMircea Trofin Counters: [ 10 ] 580*b15845c0SMircea Trofin - Guid: 1003 581*b15845c0SMircea Trofin Counters: [ 12 ] 582*b15845c0SMircea Trofin - - Guid: 1002 583*b15845c0SMircea Trofin Counters: [ 11 ] 584*b15845c0SMircea Trofin Callsites: 585*b15845c0SMircea Trofin - - Guid: 1004 586*b15845c0SMircea Trofin Counters: [ 13 ] 587*b15845c0SMircea Trofin - Guid: 1005 588*b15845c0SMircea Trofin Counters: [ 2 ] 589*b15845c0SMircea Trofin Callsites: 590*b15845c0SMircea Trofin - - Guid: 1000 591*b15845c0SMircea Trofin Counters: [ 1, 102, 204 ] 592*b15845c0SMircea Trofin Callsites: 593*b15845c0SMircea Trofin - - Guid: 1001 594*b15845c0SMircea Trofin Counters: [ 101 ] 595*b15845c0SMircea Trofin - Guid: 1003 596*b15845c0SMircea Trofin Counters: [ 103 ] 597*b15845c0SMircea Trofin - - Guid: 1002 598*b15845c0SMircea Trofin Counters: [ 102 ] 599*b15845c0SMircea Trofin Callsites: 600*b15845c0SMircea Trofin - - Guid: 1004 601*b15845c0SMircea Trofin Counters: [ 104 ] 602*b15845c0SMircea Trofin )yaml"; 603*b15845c0SMircea Trofin EXPECT_EQ(Expected, Str); 60473c3b733SMircea Trofin } 605