@@ -101,4 +101,123 @@ declare !dbg !19 void @_Z2f3v()
101101 EXPECT_THAT (CallSites[2 ],
102102 Pair (FieldsAre (2U , 9U ), IndexedMemProfRecord::getGUID (" _Z2f3v" )));
103103}
104+
105+ TEST (MemProf, ExtractDirectCallsFromIRInline) {
106+ // The following IR is generated from:
107+ //
108+ // void f1();
109+ // static inline void f2() {
110+ // // For an interesting line number.
111+ // f1();
112+ // }
113+ // static inline void f3() {
114+ // /****/ f2(); // For an interesting column number.
115+ // }
116+ //
117+ // void g1();
118+ // void g2();
119+ // static inline void g3() {
120+ // /**/ g1(); // For an interesting column number.
121+ // g2();
122+ // }
123+ //
124+ // void foo() {
125+ // f3();
126+ // /***/ g3(); // For an interesting column number.
127+ // }
128+ StringRef IR = R"IR(
129+ define dso_local void @_Z3foov() local_unnamed_addr !dbg !10 {
130+ entry:
131+ tail call void @_Z2f1v(), !dbg !13
132+ tail call void @_Z2g1v(), !dbg !18
133+ tail call void @_Z2g2v(), !dbg !21
134+ ret void, !dbg !22
135+ }
136+
137+ declare !dbg !23 void @_Z2f1v() local_unnamed_addr
138+
139+ declare !dbg !24 void @_Z2g1v() local_unnamed_addr
140+
141+ declare !dbg !25 void @_Z2g2v() local_unnamed_addr
142+
143+ !llvm.dbg.cu = !{!0}
144+ !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
145+ !llvm.ident = !{!9}
146+
147+ !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)
148+ !1 = !DIFile(filename: "foobar.cc", directory: "/")
149+ !2 = !{i32 7, !"Dwarf Version", i32 5}
150+ !3 = !{i32 2, !"Debug Info Version", i32 3}
151+ !4 = !{i32 1, !"wchar_size", i32 4}
152+ !5 = !{i32 1, !"MemProfProfileFilename", !"memprof.profraw"}
153+ !6 = !{i32 8, !"PIC Level", i32 2}
154+ !7 = !{i32 7, !"PIE Level", i32 2}
155+ !8 = !{i32 7, !"uwtable", i32 2}
156+ !9 = !{!"clang"}
157+ !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)
158+ !11 = !DISubroutineType(types: !12)
159+ !12 = !{}
160+ !13 = !DILocation(line: 4, column: 3, scope: !14, inlinedAt: !15)
161+ !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)
162+ !15 = distinct !DILocation(line: 7, column: 10, scope: !16, inlinedAt: !17)
163+ !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)
164+ !17 = distinct !DILocation(line: 18, column: 3, scope: !10)
165+ !18 = !DILocation(line: 13, column: 8, scope: !19, inlinedAt: !20)
166+ !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)
167+ !20 = distinct !DILocation(line: 19, column: 9, scope: !10)
168+ !21 = !DILocation(line: 14, column: 3, scope: !19, inlinedAt: !20)
169+ !22 = !DILocation(line: 20, column: 1, scope: !10)
170+ !23 = !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 1, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
171+ !24 = !DISubprogram(name: "g1", linkageName: "_Z2g1v", scope: !1, file: !1, line: 10, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
172+ !25 = !DISubprogram(name: "g2", linkageName: "_Z2g2v", scope: !1, file: !1, line: 11, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
173+ )IR" ;
174+
175+ LLVMContext Ctx;
176+ SMDiagnostic Err;
177+ std::unique_ptr<Module> M = parseAssemblyString (IR, Err, Ctx);
178+ ASSERT_TRUE (M);
179+
180+ auto Calls = extractCallsFromIR (*M);
181+
182+ // Expect exactly 4 callers.
183+ ASSERT_THAT (Calls, SizeIs (4 ));
184+
185+ // Verify each key-value pair.
186+
187+ auto FooIt = Calls.find (IndexedMemProfRecord::getGUID (" _Z3foov" ));
188+ ASSERT_NE (FooIt, Calls.end ());
189+ const auto &[FooCallerGUID, FooCallSites] = *FooIt;
190+ EXPECT_EQ (FooCallerGUID, IndexedMemProfRecord::getGUID (" _Z3foov" ));
191+ ASSERT_THAT (FooCallSites, SizeIs (2 ));
192+ EXPECT_THAT (FooCallSites[0 ], Pair (FieldsAre (1U , 3U ),
193+ IndexedMemProfRecord::getGUID (" _ZL2f3v" )));
194+ EXPECT_THAT (FooCallSites[1 ], Pair (FieldsAre (2U , 9U ),
195+ IndexedMemProfRecord::getGUID (" _ZL2g3v" )));
196+
197+ auto F2It = Calls.find (IndexedMemProfRecord::getGUID (" _ZL2f2v" ));
198+ ASSERT_NE (F2It, Calls.end ());
199+ const auto &[F2CallerGUID, F2CallSites] = *F2It;
200+ EXPECT_EQ (F2CallerGUID, IndexedMemProfRecord::getGUID (" _ZL2f2v" ));
201+ ASSERT_THAT (F2CallSites, SizeIs (1 ));
202+ EXPECT_THAT (F2CallSites[0 ],
203+ Pair (FieldsAre (2U , 3U ), IndexedMemProfRecord::getGUID (" _Z2f1v" )));
204+
205+ auto F3It = Calls.find (IndexedMemProfRecord::getGUID (" _ZL2f3v" ));
206+ ASSERT_NE (F3It, Calls.end ());
207+ const auto &[F3CallerGUID, F3CallSites] = *F3It;
208+ EXPECT_EQ (F3CallerGUID, IndexedMemProfRecord::getGUID (" _ZL2f3v" ));
209+ ASSERT_THAT (F3CallSites, SizeIs (1 ));
210+ EXPECT_THAT (F3CallSites[0 ], Pair (FieldsAre (1U , 10U ),
211+ IndexedMemProfRecord::getGUID (" _ZL2f2v" )));
212+
213+ auto G3It = Calls.find (IndexedMemProfRecord::getGUID (" _ZL2g3v" ));
214+ ASSERT_NE (G3It, Calls.end ());
215+ const auto &[G3CallerGUID, G3CallSites] = *G3It;
216+ EXPECT_EQ (G3CallerGUID, IndexedMemProfRecord::getGUID (" _ZL2g3v" ));
217+ ASSERT_THAT (G3CallSites, SizeIs (2 ));
218+ EXPECT_THAT (G3CallSites[0 ],
219+ Pair (FieldsAre (1U , 8U ), IndexedMemProfRecord::getGUID (" _Z2g1v" )));
220+ EXPECT_THAT (G3CallSites[1 ],
221+ Pair (FieldsAre (2U , 3U ), IndexedMemProfRecord::getGUID (" _Z2g2v" )));
222+ }
104223} // namespace
0 commit comments