xref: /llvm-project/llvm/unittests/Transforms/Instrumentation/MemProfUseTest.cpp (revision ad635b4168213293feda4c0925c6df4501e41d52)
1e189d619SKazu Hirata //===- MemProfUseTest.cpp - MemProf use tests -----------------------------===//
2e189d619SKazu Hirata //
3e189d619SKazu Hirata // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e189d619SKazu Hirata // See https://llvm.org/LICENSE.txt for license information.
5e189d619SKazu Hirata // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e189d619SKazu Hirata //
7e189d619SKazu Hirata //===----------------------------------------------------------------------===//
8e189d619SKazu Hirata 
995554cbdSKazu Hirata #include "llvm/Analysis/TargetLibraryInfo.h"
10e189d619SKazu Hirata #include "llvm/AsmParser/Parser.h"
11e189d619SKazu Hirata #include "llvm/IR/LLVMContext.h"
12e189d619SKazu Hirata #include "llvm/IR/Module.h"
1395554cbdSKazu Hirata #include "llvm/Passes/PassBuilder.h"
14a2e266b3SKazu Hirata #include "llvm/ProfileData/InstrProfReader.h"
15a2e266b3SKazu Hirata #include "llvm/ProfileData/InstrProfWriter.h"
16e189d619SKazu Hirata #include "llvm/ProfileData/MemProf.h"
17e189d619SKazu Hirata #include "llvm/Support/SourceMgr.h"
18a2e266b3SKazu Hirata #include "llvm/Testing/Support/Error.h"
19e189d619SKazu Hirata #include "llvm/Transforms/Instrumentation/MemProfiler.h"
20e189d619SKazu Hirata 
21e189d619SKazu Hirata #include "gmock/gmock.h"
22e189d619SKazu Hirata #include "gtest/gtest.h"
23e189d619SKazu Hirata 
24624e89bcSKazu Hirata namespace llvm {
25624e89bcSKazu Hirata namespace memprof {
26e189d619SKazu Hirata namespace {
27a2e266b3SKazu Hirata using testing::Contains;
28a2e266b3SKazu Hirata using testing::ElementsAre;
29e189d619SKazu Hirata using testing::Pair;
30e189d619SKazu Hirata using testing::SizeIs;
31a2e266b3SKazu Hirata using testing::UnorderedElementsAre;
32e189d619SKazu Hirata 
33e189d619SKazu Hirata TEST(MemProf, ExtractDirectCallsFromIR) {
34e189d619SKazu Hirata   // The following IR is generated from:
35e189d619SKazu Hirata   //
36e189d619SKazu Hirata   // void f1();
37e189d619SKazu Hirata   // void f2();
38e189d619SKazu Hirata   // void f3();
39e189d619SKazu Hirata   //
40e189d619SKazu Hirata   // void foo() {
41e189d619SKazu Hirata   //   f1();
42e189d619SKazu Hirata   //   f2(); f3();
43e189d619SKazu Hirata   // }
44e189d619SKazu Hirata   StringRef IR = R"IR(
45e189d619SKazu Hirata define dso_local void @_Z3foov() !dbg !10 {
46e189d619SKazu Hirata entry:
47e189d619SKazu Hirata   call void @_Z2f1v(), !dbg !13
48e189d619SKazu Hirata   call void @_Z2f2v(), !dbg !14
49e189d619SKazu Hirata   call void @_Z2f3v(), !dbg !15
50e189d619SKazu Hirata   ret void, !dbg !16
51e189d619SKazu Hirata }
52e189d619SKazu Hirata 
53e189d619SKazu Hirata declare !dbg !17 void @_Z2f1v()
54e189d619SKazu Hirata 
55e189d619SKazu Hirata declare !dbg !18 void @_Z2f2v()
56e189d619SKazu Hirata 
57e189d619SKazu Hirata declare !dbg !19 void @_Z2f3v()
58e189d619SKazu Hirata 
59e189d619SKazu Hirata !llvm.dbg.cu = !{!0}
60e189d619SKazu Hirata !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
61e189d619SKazu Hirata !llvm.ident = !{!9}
62e189d619SKazu Hirata 
63e189d619SKazu Hirata !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false, debugInfoForProfiling: true, nameTableKind: None)
64e189d619SKazu Hirata !1 = !DIFile(filename: "foobar.cc", directory: "/")
65e189d619SKazu Hirata !2 = !{i32 7, !"Dwarf Version", i32 5}
66e189d619SKazu Hirata !3 = !{i32 2, !"Debug Info Version", i32 3}
67e189d619SKazu Hirata !4 = !{i32 1, !"wchar_size", i32 4}
68e189d619SKazu Hirata !5 = !{i32 1, !"MemProfProfileFilename", !"memprof.profraw"}
69e189d619SKazu Hirata !6 = !{i32 8, !"PIC Level", i32 2}
70e189d619SKazu Hirata !7 = !{i32 7, !"PIE Level", i32 2}
71e189d619SKazu Hirata !8 = !{i32 7, !"uwtable", i32 2}
72e189d619SKazu Hirata !9 = !{!"clang"}
73e189d619SKazu Hirata !10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 5, type: !11, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)
74e189d619SKazu Hirata !11 = !DISubroutineType(types: !12)
75e189d619SKazu Hirata !12 = !{}
76e189d619SKazu Hirata !13 = !DILocation(line: 6, column: 3, scope: !10)
77e189d619SKazu Hirata !14 = !DILocation(line: 7, column: 3, scope: !10)
78e189d619SKazu Hirata !15 = !DILocation(line: 7, column: 9, scope: !10)
79e189d619SKazu Hirata !16 = !DILocation(line: 8, column: 1, scope: !10)
80e189d619SKazu Hirata !17 = !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 1, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
81e189d619SKazu Hirata !18 = !DISubprogram(name: "f2", linkageName: "_Z2f2v", scope: !1, file: !1, line: 2, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
82e189d619SKazu Hirata !19 = !DISubprogram(name: "f3", linkageName: "_Z2f3v", scope: !1, file: !1, line: 3, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
83e189d619SKazu Hirata )IR";
84e189d619SKazu Hirata 
85e189d619SKazu Hirata   LLVMContext Ctx;
86e189d619SKazu Hirata   SMDiagnostic Err;
87e189d619SKazu Hirata   std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Ctx);
88e189d619SKazu Hirata   ASSERT_TRUE(M);
89e189d619SKazu Hirata 
9095554cbdSKazu Hirata   auto *F = M->getFunction("_Z3foov");
9195554cbdSKazu Hirata   ASSERT_NE(F, nullptr);
9295554cbdSKazu Hirata 
9395554cbdSKazu Hirata   TargetLibraryInfoWrapperPass WrapperPass;
9495554cbdSKazu Hirata   auto &TLI = WrapperPass.getTLI(*F);
9595554cbdSKazu Hirata   auto Calls = extractCallsFromIR(*M, TLI);
96e189d619SKazu Hirata 
97e189d619SKazu Hirata   // Expect exactly one caller.
98e189d619SKazu Hirata   ASSERT_THAT(Calls, SizeIs(1));
99e189d619SKazu Hirata 
100e189d619SKazu Hirata   auto It = Calls.begin();
101e189d619SKazu Hirata   ASSERT_NE(It, Calls.end());
102e189d619SKazu Hirata 
103e189d619SKazu Hirata   const auto &[CallerGUID, CallSites] = *It;
104e189d619SKazu Hirata   EXPECT_EQ(CallerGUID, IndexedMemProfRecord::getGUID("_Z3foov"));
105e189d619SKazu Hirata 
106e189d619SKazu Hirata   // Verify that call sites show up in the ascending order of their source
107e189d619SKazu Hirata   // locations.
108*ad635b41SKazu Hirata   EXPECT_THAT(
109*ad635b41SKazu Hirata       CallSites,
110*ad635b41SKazu Hirata       ElementsAre(
111*ad635b41SKazu Hirata           Pair(LineLocation(1, 3), IndexedMemProfRecord::getGUID("_Z2f1v")),
112*ad635b41SKazu Hirata           Pair(LineLocation(2, 3), IndexedMemProfRecord::getGUID("_Z2f2v")),
113*ad635b41SKazu Hirata           Pair(LineLocation(2, 9), IndexedMemProfRecord::getGUID("_Z2f3v"))));
114e189d619SKazu Hirata }
115c6183244SKazu Hirata 
116c6183244SKazu Hirata TEST(MemProf, ExtractDirectCallsFromIRInline) {
117c6183244SKazu Hirata   // The following IR is generated from:
118c6183244SKazu Hirata   //
119c6183244SKazu Hirata   // void f1();
120c6183244SKazu Hirata   // static inline void f2() {
121c6183244SKazu Hirata   //   // For an interesting line number.
122c6183244SKazu Hirata   //   f1();
123c6183244SKazu Hirata   // }
124c6183244SKazu Hirata   // static inline void f3() {
125c6183244SKazu Hirata   //   /****/ f2();  // For an interesting column number.
126c6183244SKazu Hirata   // }
127c6183244SKazu Hirata   //
128c6183244SKazu Hirata   // void g1();
129c6183244SKazu Hirata   // void g2();
130c6183244SKazu Hirata   // static inline void g3() {
131c6183244SKazu Hirata   //   /**/ g1();  // For an interesting column number.
132c6183244SKazu Hirata   //   g2();
133c6183244SKazu Hirata   // }
134c6183244SKazu Hirata   //
135c6183244SKazu Hirata   // void foo() {
136c6183244SKazu Hirata   //   f3();
137c6183244SKazu Hirata   //   /***/ g3();  // For an interesting column number.
138c6183244SKazu Hirata   // }
139c6183244SKazu Hirata   StringRef IR = R"IR(
140c6183244SKazu Hirata define dso_local void @_Z3foov() local_unnamed_addr !dbg !10 {
141c6183244SKazu Hirata entry:
142c6183244SKazu Hirata   tail call void @_Z2f1v(), !dbg !13
143c6183244SKazu Hirata   tail call void @_Z2g1v(), !dbg !18
144c6183244SKazu Hirata   tail call void @_Z2g2v(), !dbg !21
145c6183244SKazu Hirata   ret void, !dbg !22
146c6183244SKazu Hirata }
147c6183244SKazu Hirata 
148c6183244SKazu Hirata declare !dbg !23 void @_Z2f1v() local_unnamed_addr
149c6183244SKazu Hirata 
150c6183244SKazu Hirata declare !dbg !24 void @_Z2g1v() local_unnamed_addr
151c6183244SKazu Hirata 
152c6183244SKazu Hirata declare !dbg !25 void @_Z2g2v() local_unnamed_addr
153c6183244SKazu Hirata 
154c6183244SKazu Hirata !llvm.dbg.cu = !{!0}
155c6183244SKazu Hirata !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
156c6183244SKazu Hirata !llvm.ident = !{!9}
157c6183244SKazu Hirata 
158c6183244SKazu Hirata !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false, debugInfoForProfiling: true, nameTableKind: None)
159c6183244SKazu Hirata !1 = !DIFile(filename: "foobar.cc", directory: "/")
160c6183244SKazu Hirata !2 = !{i32 7, !"Dwarf Version", i32 5}
161c6183244SKazu Hirata !3 = !{i32 2, !"Debug Info Version", i32 3}
162c6183244SKazu Hirata !4 = !{i32 1, !"wchar_size", i32 4}
163c6183244SKazu Hirata !5 = !{i32 1, !"MemProfProfileFilename", !"memprof.profraw"}
164c6183244SKazu Hirata !6 = !{i32 8, !"PIC Level", i32 2}
165c6183244SKazu Hirata !7 = !{i32 7, !"PIE Level", i32 2}
166c6183244SKazu Hirata !8 = !{i32 7, !"uwtable", i32 2}
167c6183244SKazu Hirata !9 = !{!"clang"}
168c6183244SKazu Hirata !10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 17, type: !11, scopeLine: 17, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)
169c6183244SKazu Hirata !11 = !DISubroutineType(types: !12)
170c6183244SKazu Hirata !12 = !{}
171c6183244SKazu Hirata !13 = !DILocation(line: 4, column: 3, scope: !14, inlinedAt: !15)
172c6183244SKazu Hirata !14 = distinct !DISubprogram(name: "f2", linkageName: "_ZL2f2v", scope: !1, file: !1, line: 2, type: !11, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0)
173c6183244SKazu Hirata !15 = distinct !DILocation(line: 7, column: 10, scope: !16, inlinedAt: !17)
174c6183244SKazu Hirata !16 = distinct !DISubprogram(name: "f3", linkageName: "_ZL2f3v", scope: !1, file: !1, line: 6, type: !11, scopeLine: 6, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0)
175c6183244SKazu Hirata !17 = distinct !DILocation(line: 18, column: 3, scope: !10)
176c6183244SKazu Hirata !18 = !DILocation(line: 13, column: 8, scope: !19, inlinedAt: !20)
177c6183244SKazu Hirata !19 = distinct !DISubprogram(name: "g3", linkageName: "_ZL2g3v", scope: !1, file: !1, line: 12, type: !11, scopeLine: 12, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0)
178c6183244SKazu Hirata !20 = distinct !DILocation(line: 19, column: 9, scope: !10)
179c6183244SKazu Hirata !21 = !DILocation(line: 14, column: 3, scope: !19, inlinedAt: !20)
180c6183244SKazu Hirata !22 = !DILocation(line: 20, column: 1, scope: !10)
181c6183244SKazu Hirata !23 = !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 1, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
182c6183244SKazu Hirata !24 = !DISubprogram(name: "g1", linkageName: "_Z2g1v", scope: !1, file: !1, line: 10, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
183c6183244SKazu Hirata !25 = !DISubprogram(name: "g2", linkageName: "_Z2g2v", scope: !1, file: !1, line: 11, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
184c6183244SKazu Hirata )IR";
185c6183244SKazu Hirata 
186c6183244SKazu Hirata   LLVMContext Ctx;
187c6183244SKazu Hirata   SMDiagnostic Err;
188c6183244SKazu Hirata   std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Ctx);
189c6183244SKazu Hirata   ASSERT_TRUE(M);
190c6183244SKazu Hirata 
19195554cbdSKazu Hirata   auto *F = M->getFunction("_Z3foov");
19295554cbdSKazu Hirata   ASSERT_NE(F, nullptr);
19395554cbdSKazu Hirata 
19495554cbdSKazu Hirata   TargetLibraryInfoWrapperPass WrapperPass;
19595554cbdSKazu Hirata   auto &TLI = WrapperPass.getTLI(*F);
19695554cbdSKazu Hirata   auto Calls = extractCallsFromIR(*M, TLI);
197c6183244SKazu Hirata 
198c6183244SKazu Hirata   // Expect exactly 4 callers.
199c6183244SKazu Hirata   ASSERT_THAT(Calls, SizeIs(4));
200c6183244SKazu Hirata 
201c6183244SKazu Hirata   // Verify each key-value pair.
202c6183244SKazu Hirata 
203c6183244SKazu Hirata   auto FooIt = Calls.find(IndexedMemProfRecord::getGUID("_Z3foov"));
204c6183244SKazu Hirata   ASSERT_NE(FooIt, Calls.end());
205c6183244SKazu Hirata   const auto &[FooCallerGUID, FooCallSites] = *FooIt;
206c6183244SKazu Hirata   EXPECT_EQ(FooCallerGUID, IndexedMemProfRecord::getGUID("_Z3foov"));
207*ad635b41SKazu Hirata   EXPECT_THAT(
208*ad635b41SKazu Hirata       FooCallSites,
209*ad635b41SKazu Hirata       ElementsAre(
210*ad635b41SKazu Hirata           Pair(LineLocation(1, 3), IndexedMemProfRecord::getGUID("_ZL2f3v")),
211*ad635b41SKazu Hirata           Pair(LineLocation(2, 9), IndexedMemProfRecord::getGUID("_ZL2g3v"))));
212c6183244SKazu Hirata 
213c6183244SKazu Hirata   auto F2It = Calls.find(IndexedMemProfRecord::getGUID("_ZL2f2v"));
214c6183244SKazu Hirata   ASSERT_NE(F2It, Calls.end());
215c6183244SKazu Hirata   const auto &[F2CallerGUID, F2CallSites] = *F2It;
216c6183244SKazu Hirata   EXPECT_EQ(F2CallerGUID, IndexedMemProfRecord::getGUID("_ZL2f2v"));
217*ad635b41SKazu Hirata   EXPECT_THAT(F2CallSites,
218*ad635b41SKazu Hirata               ElementsAre(Pair(LineLocation(2, 3),
219*ad635b41SKazu Hirata                                IndexedMemProfRecord::getGUID("_Z2f1v"))));
220c6183244SKazu Hirata 
221c6183244SKazu Hirata   auto F3It = Calls.find(IndexedMemProfRecord::getGUID("_ZL2f3v"));
222c6183244SKazu Hirata   ASSERT_NE(F3It, Calls.end());
223c6183244SKazu Hirata   const auto &[F3CallerGUID, F3CallSites] = *F3It;
224c6183244SKazu Hirata   EXPECT_EQ(F3CallerGUID, IndexedMemProfRecord::getGUID("_ZL2f3v"));
225*ad635b41SKazu Hirata   EXPECT_THAT(F3CallSites,
226*ad635b41SKazu Hirata               ElementsAre(Pair(LineLocation(1, 10),
227*ad635b41SKazu Hirata                                IndexedMemProfRecord::getGUID("_ZL2f2v"))));
228c6183244SKazu Hirata 
229c6183244SKazu Hirata   auto G3It = Calls.find(IndexedMemProfRecord::getGUID("_ZL2g3v"));
230c6183244SKazu Hirata   ASSERT_NE(G3It, Calls.end());
231c6183244SKazu Hirata   const auto &[G3CallerGUID, G3CallSites] = *G3It;
232c6183244SKazu Hirata   EXPECT_EQ(G3CallerGUID, IndexedMemProfRecord::getGUID("_ZL2g3v"));
233*ad635b41SKazu Hirata   EXPECT_THAT(
234*ad635b41SKazu Hirata       G3CallSites,
235*ad635b41SKazu Hirata       ElementsAre(
236*ad635b41SKazu Hirata           Pair(LineLocation(1, 8), IndexedMemProfRecord::getGUID("_Z2g1v")),
237*ad635b41SKazu Hirata           Pair(LineLocation(2, 3), IndexedMemProfRecord::getGUID("_Z2g2v"))));
238c6183244SKazu Hirata }
23995554cbdSKazu Hirata 
24095554cbdSKazu Hirata TEST(MemProf, ExtractDirectCallsFromIRCallingNew) {
24195554cbdSKazu Hirata   // The following IR is generated from:
24295554cbdSKazu Hirata   //
24395554cbdSKazu Hirata   // int *foo() {
24495554cbdSKazu Hirata   //   return ::new (int);
24595554cbdSKazu Hirata   // }
24695554cbdSKazu Hirata   StringRef IR = R"IR(
24795554cbdSKazu Hirata define dso_local noundef ptr @_Z3foov() #0 !dbg !10 {
24895554cbdSKazu Hirata entry:
24995554cbdSKazu Hirata   %call = call noalias noundef nonnull ptr @_Znwm(i64 noundef 4) #2, !dbg !13
25095554cbdSKazu Hirata   ret ptr %call, !dbg !14
25195554cbdSKazu Hirata }
25295554cbdSKazu Hirata 
25395554cbdSKazu Hirata ; Function Attrs: nobuiltin allocsize(0)
25495554cbdSKazu Hirata declare noundef nonnull ptr @_Znwm(i64 noundef) #1
25595554cbdSKazu Hirata 
25695554cbdSKazu Hirata attributes #0 = { mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
25795554cbdSKazu Hirata attributes #1 = { nobuiltin allocsize(0) "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
25895554cbdSKazu Hirata attributes #2 = { builtin allocsize(0) }
25995554cbdSKazu Hirata 
26095554cbdSKazu Hirata !llvm.dbg.cu = !{!0}
26195554cbdSKazu Hirata !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
26295554cbdSKazu Hirata !llvm.ident = !{!9}
26395554cbdSKazu Hirata 
26495554cbdSKazu Hirata !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false, debugInfoForProfiling: true, nameTableKind: None)
26595554cbdSKazu Hirata !1 = !DIFile(filename: "foobar.cc", directory: "/")
26695554cbdSKazu Hirata !2 = !{i32 7, !"Dwarf Version", i32 5}
26795554cbdSKazu Hirata !3 = !{i32 2, !"Debug Info Version", i32 3}
26895554cbdSKazu Hirata !4 = !{i32 1, !"wchar_size", i32 4}
26995554cbdSKazu Hirata !5 = !{i32 1, !"MemProfProfileFilename", !"memprof.profraw"}
27095554cbdSKazu Hirata !6 = !{i32 8, !"PIC Level", i32 2}
27195554cbdSKazu Hirata !7 = !{i32 7, !"PIE Level", i32 2}
27295554cbdSKazu Hirata !8 = !{i32 7, !"uwtable", i32 2}
27395554cbdSKazu Hirata !9 = !{!"clang"}
27495554cbdSKazu Hirata !10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)
27595554cbdSKazu Hirata !11 = !DISubroutineType(types: !12)
27695554cbdSKazu Hirata !12 = !{}
27795554cbdSKazu Hirata !13 = !DILocation(line: 2, column: 10, scope: !10)
27895554cbdSKazu Hirata !14 = !DILocation(line: 2, column: 3, scope: !10)
27995554cbdSKazu Hirata )IR";
28095554cbdSKazu Hirata 
28195554cbdSKazu Hirata   LLVMContext Ctx;
28295554cbdSKazu Hirata   SMDiagnostic Err;
28395554cbdSKazu Hirata   std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Ctx);
28495554cbdSKazu Hirata   ASSERT_TRUE(M);
28595554cbdSKazu Hirata 
28695554cbdSKazu Hirata   auto *F = M->getFunction("_Z3foov");
28795554cbdSKazu Hirata   ASSERT_NE(F, nullptr);
28895554cbdSKazu Hirata 
28995554cbdSKazu Hirata   TargetLibraryInfoWrapperPass WrapperPass;
29095554cbdSKazu Hirata   auto &TLI = WrapperPass.getTLI(*F);
29195554cbdSKazu Hirata   auto Calls = extractCallsFromIR(*M, TLI);
29295554cbdSKazu Hirata 
29395554cbdSKazu Hirata   // Expect exactly one caller.
29495554cbdSKazu Hirata   ASSERT_THAT(Calls, SizeIs(1));
29595554cbdSKazu Hirata 
29695554cbdSKazu Hirata   // Verify each key-value pair.
29795554cbdSKazu Hirata 
29895554cbdSKazu Hirata   auto FooIt = Calls.find(IndexedMemProfRecord::getGUID("_Z3foov"));
29995554cbdSKazu Hirata   ASSERT_NE(FooIt, Calls.end());
30095554cbdSKazu Hirata   const auto &[FooCallerGUID, FooCallSites] = *FooIt;
30195554cbdSKazu Hirata   EXPECT_EQ(FooCallerGUID, IndexedMemProfRecord::getGUID("_Z3foov"));
302*ad635b41SKazu Hirata   EXPECT_THAT(FooCallSites, ElementsAre(Pair(LineLocation(1, 10), 0)));
30395554cbdSKazu Hirata }
304a2e266b3SKazu Hirata 
305a2e266b3SKazu Hirata // Populate those fields returned by getHotColdSchema.
306a2e266b3SKazu Hirata MemInfoBlock makePartialMIB() {
307a2e266b3SKazu Hirata   MemInfoBlock MIB;
308a2e266b3SKazu Hirata   MIB.AllocCount = 1;
309a2e266b3SKazu Hirata   MIB.TotalSize = 5;
310a2e266b3SKazu Hirata   MIB.TotalLifetime = 10;
311a2e266b3SKazu Hirata   MIB.TotalLifetimeAccessDensity = 23;
312a2e266b3SKazu Hirata   return MIB;
313a2e266b3SKazu Hirata }
314a2e266b3SKazu Hirata 
315a2e266b3SKazu Hirata IndexedMemProfRecord
316624e89bcSKazu Hirata makeRecordV2(std::initializer_list<CallStackId> AllocFrames,
317624e89bcSKazu Hirata              std::initializer_list<CallStackId> CallSiteFrames,
318624e89bcSKazu Hirata              const MemInfoBlock &Block, const MemProfSchema &Schema) {
319624e89bcSKazu Hirata   IndexedMemProfRecord MR;
320624e89bcSKazu Hirata   for (const auto &CSId : AllocFrames)
3214acba069SKazu Hirata     MR.AllocSites.emplace_back(CSId, Block, Schema);
322a2e266b3SKazu Hirata   for (const auto &CSId : CallSiteFrames)
323a2e266b3SKazu Hirata     MR.CallSiteIds.push_back(CSId);
324a2e266b3SKazu Hirata   return MR;
325a2e266b3SKazu Hirata }
326a2e266b3SKazu Hirata 
327a2e266b3SKazu Hirata static const auto Err = [](Error E) {
328a2e266b3SKazu Hirata   FAIL() << E;
329a2e266b3SKazu Hirata   consumeError(std::move(E));
330a2e266b3SKazu Hirata };
331a2e266b3SKazu Hirata 
332a2e266b3SKazu Hirata // Make sure that we can undrift direct calls.
333a2e266b3SKazu Hirata TEST(MemProf, ComputeUndriftingMap) {
334a2e266b3SKazu Hirata   // Suppose that the source code has changed from:
335a2e266b3SKazu Hirata   //
336a2e266b3SKazu Hirata   //   void bar();
337a2e266b3SKazu Hirata   //   void baz();
338a2e266b3SKazu Hirata   //   void zzz();
339a2e266b3SKazu Hirata   //
340a2e266b3SKazu Hirata   //   void foo() {
341a2e266b3SKazu Hirata   //     /**/ bar();  // LineLocation(1, 8)
342a2e266b3SKazu Hirata   //     zzz();       // LineLocation(2, 3)
343a2e266b3SKazu Hirata   //     baz();       // LineLocation(3, 3)
344a2e266b3SKazu Hirata   //   }
345a2e266b3SKazu Hirata   //
346a2e266b3SKazu Hirata   // to:
347a2e266b3SKazu Hirata   //
348a2e266b3SKazu Hirata   //   void bar();
349a2e266b3SKazu Hirata   //   void baz();
350a2e266b3SKazu Hirata   //
351a2e266b3SKazu Hirata   //   void foo() {
352a2e266b3SKazu Hirata   //     bar();        // LineLocation(1, 3)
353a2e266b3SKazu Hirata   //     /**/ baz();   // LineLocation(2, 8)
354a2e266b3SKazu Hirata   //   }
355a2e266b3SKazu Hirata   //
356a2e266b3SKazu Hirata   // Notice that the calls to bar and baz have drifted while zzz has been
357a2e266b3SKazu Hirata   // removed.
358a2e266b3SKazu Hirata   StringRef IR = R"IR(
359a2e266b3SKazu Hirata define dso_local void @_Z3foov() #0 !dbg !10 {
360a2e266b3SKazu Hirata entry:
361a2e266b3SKazu Hirata   call void @_Z3barv(), !dbg !13
362a2e266b3SKazu Hirata   call void @_Z3bazv(), !dbg !14
363a2e266b3SKazu Hirata   ret void, !dbg !15
364a2e266b3SKazu Hirata }
365a2e266b3SKazu Hirata 
366a2e266b3SKazu Hirata declare !dbg !16 void @_Z3barv() #1
367a2e266b3SKazu Hirata 
368a2e266b3SKazu Hirata declare !dbg !17 void @_Z3bazv() #1
369a2e266b3SKazu Hirata 
370a2e266b3SKazu Hirata attributes #0 = { mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
371a2e266b3SKazu Hirata attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
372a2e266b3SKazu Hirata 
373a2e266b3SKazu Hirata !llvm.dbg.cu = !{!0}
374a2e266b3SKazu Hirata !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
375a2e266b3SKazu Hirata !llvm.ident = !{!9}
376a2e266b3SKazu Hirata 
377a2e266b3SKazu Hirata !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false, debugInfoForProfiling: true, nameTableKind: None)
378a2e266b3SKazu Hirata !1 = !DIFile(filename: "foobar.cc", directory: "/")
379a2e266b3SKazu Hirata !2 = !{i32 7, !"Dwarf Version", i32 5}
380a2e266b3SKazu Hirata !3 = !{i32 2, !"Debug Info Version", i32 3}
381a2e266b3SKazu Hirata !4 = !{i32 1, !"wchar_size", i32 4}
382a2e266b3SKazu Hirata !5 = !{i32 1, !"MemProfProfileFilename", !"memprof.profraw"}
383a2e266b3SKazu Hirata !6 = !{i32 8, !"PIC Level", i32 2}
384a2e266b3SKazu Hirata !7 = !{i32 7, !"PIE Level", i32 2}
385a2e266b3SKazu Hirata !8 = !{i32 7, !"uwtable", i32 2}
386a2e266b3SKazu Hirata !9 = !{!"clang"}
387a2e266b3SKazu Hirata !10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 4, type: !11, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)
388a2e266b3SKazu Hirata !11 = !DISubroutineType(types: !12)
389a2e266b3SKazu Hirata !12 = !{}
390a2e266b3SKazu Hirata !13 = !DILocation(line: 5, column: 3, scope: !10)
391a2e266b3SKazu Hirata !14 = !DILocation(line: 6, column: 8, scope: !10)
392a2e266b3SKazu Hirata !15 = !DILocation(line: 7, column: 1, scope: !10)
393a2e266b3SKazu Hirata !16 = !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1, file: !1, line: 1, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
394a2e266b3SKazu Hirata !17 = !DISubprogram(name: "baz", linkageName: "_Z3bazv", scope: !1, file: !1, line: 2, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
395a2e266b3SKazu Hirata )IR";
396a2e266b3SKazu Hirata 
397a2e266b3SKazu Hirata   LLVMContext Ctx;
398a2e266b3SKazu Hirata   SMDiagnostic SMErr;
399a2e266b3SKazu Hirata   std::unique_ptr<Module> M = parseAssemblyString(IR, SMErr, Ctx);
400a2e266b3SKazu Hirata   ASSERT_TRUE(M);
401a2e266b3SKazu Hirata 
402a2e266b3SKazu Hirata   auto *F = M->getFunction("_Z3foov");
403a2e266b3SKazu Hirata   ASSERT_NE(F, nullptr);
404a2e266b3SKazu Hirata 
405a2e266b3SKazu Hirata   TargetLibraryInfoWrapperPass WrapperPass;
406a2e266b3SKazu Hirata   auto &TLI = WrapperPass.getTLI(*F);
407a2e266b3SKazu Hirata   auto Calls = extractCallsFromIR(*M, TLI);
408a2e266b3SKazu Hirata 
409a2e266b3SKazu Hirata   uint64_t GUIDFoo = IndexedMemProfRecord::getGUID("_Z3foov");
410a2e266b3SKazu Hirata   uint64_t GUIDBar = IndexedMemProfRecord::getGUID("_Z3barv");
411a2e266b3SKazu Hirata   uint64_t GUIDBaz = IndexedMemProfRecord::getGUID("_Z3bazv");
412a2e266b3SKazu Hirata   uint64_t GUIDZzz = IndexedMemProfRecord::getGUID("_Z3zzzv");
413a2e266b3SKazu Hirata 
414a2e266b3SKazu Hirata   // Verify that extractCallsFromIR extracts caller-callee pairs as expected.
415a2e266b3SKazu Hirata   EXPECT_THAT(Calls,
416a2e266b3SKazu Hirata               UnorderedElementsAre(Pair(
417a2e266b3SKazu Hirata                   GUIDFoo, ElementsAre(Pair(LineLocation(1, 3), GUIDBar),
418a2e266b3SKazu Hirata                                        Pair(LineLocation(2, 8), GUIDBaz)))));
419a2e266b3SKazu Hirata 
420a2e266b3SKazu Hirata   llvm::InstrProfWriter Writer;
421a2e266b3SKazu Hirata   std::unique_ptr<IndexedInstrProfReader> Reader;
422a2e266b3SKazu Hirata 
423a2e266b3SKazu Hirata   const MemInfoBlock MIB = makePartialMIB();
424a2e266b3SKazu Hirata 
425624e89bcSKazu Hirata   Writer.setMemProfVersionRequested(Version3);
426a2e266b3SKazu Hirata   Writer.setMemProfFullSchema(false);
427a2e266b3SKazu Hirata 
428a2e266b3SKazu Hirata   ASSERT_THAT_ERROR(Writer.mergeProfileKind(InstrProfKind::MemProf),
429a2e266b3SKazu Hirata                     Succeeded());
430a2e266b3SKazu Hirata 
431a2e266b3SKazu Hirata   const IndexedMemProfRecord IndexedMR = makeRecordV2(
432a2e266b3SKazu Hirata       /*AllocFrames=*/{0x111, 0x222, 0x333},
433624e89bcSKazu Hirata       /*CallSiteFrames=*/{}, MIB, getHotColdSchema());
4344b3b74dfSKazu Hirata 
435624e89bcSKazu Hirata   IndexedMemProfData MemProfData;
4364b3b74dfSKazu Hirata   // The call sites within foo.
4374b3b74dfSKazu Hirata   MemProfData.Frames.try_emplace(0, GUIDFoo, 1, 8, false);
4384b3b74dfSKazu Hirata   MemProfData.Frames.try_emplace(1, GUIDFoo, 2, 3, false);
4394b3b74dfSKazu Hirata   MemProfData.Frames.try_emplace(2, GUIDFoo, 3, 3, false);
4404b3b74dfSKazu Hirata   // Line/column numbers below don't matter.
4414b3b74dfSKazu Hirata   MemProfData.Frames.try_emplace(3, GUIDBar, 9, 9, false);
4424b3b74dfSKazu Hirata   MemProfData.Frames.try_emplace(4, GUIDZzz, 9, 9, false);
4434b3b74dfSKazu Hirata   MemProfData.Frames.try_emplace(5, GUIDBaz, 9, 9, false);
4444b3b74dfSKazu Hirata   MemProfData.CallStacks.try_emplace(
445624e89bcSKazu Hirata       0x111, std::initializer_list<FrameId>{3, 0}); // bar called by foo
4464b3b74dfSKazu Hirata   MemProfData.CallStacks.try_emplace(
447624e89bcSKazu Hirata       0x222, std::initializer_list<FrameId>{4, 1}); // zzz called by foo
4484b3b74dfSKazu Hirata   MemProfData.CallStacks.try_emplace(
449624e89bcSKazu Hirata       0x333, std::initializer_list<FrameId>{5, 2}); // baz called by foo
4504b3b74dfSKazu Hirata   MemProfData.Records.try_emplace(0x9999, IndexedMR);
4514b3b74dfSKazu Hirata   Writer.addMemProfData(MemProfData, Err);
452a2e266b3SKazu Hirata 
453a2e266b3SKazu Hirata   auto Profile = Writer.writeBuffer();
454a2e266b3SKazu Hirata 
455a2e266b3SKazu Hirata   auto ReaderOrErr =
456a2e266b3SKazu Hirata       IndexedInstrProfReader::create(std::move(Profile), nullptr);
457a2e266b3SKazu Hirata   EXPECT_THAT_ERROR(ReaderOrErr.takeError(), Succeeded());
458a2e266b3SKazu Hirata   Reader = std::move(ReaderOrErr.get());
459a2e266b3SKazu Hirata 
460a2e266b3SKazu Hirata   // Verify that getMemProfCallerCalleePairs extracts caller-callee pairs as
461a2e266b3SKazu Hirata   // expected.
462a2e266b3SKazu Hirata   auto Pairs = Reader->getMemProfCallerCalleePairs();
463a2e266b3SKazu Hirata   ASSERT_THAT(Pairs, SizeIs(4));
464a2e266b3SKazu Hirata   ASSERT_THAT(
465a2e266b3SKazu Hirata       Pairs,
466a2e266b3SKazu Hirata       Contains(Pair(GUIDFoo, ElementsAre(Pair(LineLocation(1, 8), GUIDBar),
467a2e266b3SKazu Hirata                                          Pair(LineLocation(2, 3), GUIDZzz),
468a2e266b3SKazu Hirata                                          Pair(LineLocation(3, 3), GUIDBaz)))));
469a2e266b3SKazu Hirata 
470a2e266b3SKazu Hirata   // Verify that computeUndriftMap identifies undrifting opportunities:
471a2e266b3SKazu Hirata   //
472a2e266b3SKazu Hirata   //   Profile                 IR
473a2e266b3SKazu Hirata   //   (Line: 1, Column: 8) -> (Line: 1, Column: 3)
474a2e266b3SKazu Hirata   //   (Line: 3, Column: 3) -> (Line: 2, Column: 8)
475a2e266b3SKazu Hirata   auto UndriftMap = computeUndriftMap(*M, Reader.get(), TLI);
476a2e266b3SKazu Hirata   ASSERT_THAT(UndriftMap,
477a2e266b3SKazu Hirata               UnorderedElementsAre(Pair(
478a2e266b3SKazu Hirata                   GUIDFoo, UnorderedElementsAre(
479a2e266b3SKazu Hirata                                Pair(LineLocation(1, 8), LineLocation(1, 3)),
480a2e266b3SKazu Hirata                                Pair(LineLocation(3, 3), LineLocation(2, 8))))));
481a2e266b3SKazu Hirata }
482e189d619SKazu Hirata } // namespace
483624e89bcSKazu Hirata } // namespace memprof
484624e89bcSKazu Hirata } // namespace llvm
485