xref: /llvm-project/llvm/unittests/Transforms/Utils/CallPromotionUtilsTest.cpp (revision b15845c0059b06f406e33f278127d7eb41ff5ab6)
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