1 | //===- llvm/unittest/IR/BasicBlockTest.cpp - BasicBlock unit tests --------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/IR/BasicBlock.h" |
10 | #include "llvm/IR/DebugInfo.h" |
11 | #include "llvm/ADT/STLExtras.h" |
12 | #include "llvm/AsmParser/Parser.h" |
13 | #include "llvm/IR/Function.h" |
14 | #include "llvm/IR/IRBuilder.h" |
15 | #include "llvm/IR/Instruction.h" |
16 | #include "llvm/IR/Instructions.h" |
17 | #include "llvm/IR/LLVMContext.h" |
18 | #include "llvm/IR/Module.h" |
19 | #include "llvm/IR/NoFolder.h" |
20 | #include "llvm/IR/Verifier.h" |
21 | #include "llvm/Support/SourceMgr.h" |
22 | #include "gmock/gmock-matchers.h" |
23 | #include "gtest/gtest.h" |
24 | #include <memory> |
25 | |
26 | using namespace llvm; |
27 | |
28 | extern cl::opt<bool> UseNewDbgInfoFormat; |
29 | |
30 | static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { |
31 | SMDiagnostic Err; |
32 | std::unique_ptr<Module> Mod = parseAssemblyString(AsmString: IR, Err, Context&: C); |
33 | if (!Mod) |
34 | Err.print(ProgName: "BasicBlockDbgInfoTest" , S&: errs()); |
35 | return Mod; |
36 | } |
37 | |
38 | namespace { |
39 | |
40 | // We can occasionally moveAfter an instruction so that it moves to the |
41 | // position that it already resides at. This is fine -- but gets complicated |
42 | // with dbg.value intrinsics. By moving an instruction, we can end up changing |
43 | // nothing but the location of debug-info intrinsics. That has to be modelled |
44 | // by DbgVariableRecords, the dbg.value replacement. |
45 | TEST(BasicBlockDbgInfoTest, InsertAfterSelf) { |
46 | LLVMContext C; |
47 | UseNewDbgInfoFormat = true; |
48 | |
49 | std::unique_ptr<Module> M = parseIR(C, IR: R"( |
50 | define i16 @f(i16 %a) !dbg !6 { |
51 | call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11 |
52 | %b = add i16 %a, 1, !dbg !11 |
53 | call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11 |
54 | %c = add i16 %b, 1, !dbg !11 |
55 | ret i16 0, !dbg !11 |
56 | } |
57 | declare void @llvm.dbg.value(metadata, metadata, metadata) #0 |
58 | attributes #0 = { nounwind readnone speculatable willreturn } |
59 | |
60 | !llvm.dbg.cu = !{!0} |
61 | !llvm.module.flags = !{!5} |
62 | |
63 | !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) |
64 | !1 = !DIFile(filename: "t.ll", directory: "/") |
65 | !2 = !{} |
66 | !5 = !{i32 2, !"Debug Info Version", i32 3} |
67 | !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) |
68 | !7 = !DISubroutineType(types: !2) |
69 | !8 = !{!9} |
70 | !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) |
71 | !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned) |
72 | !11 = !DILocation(line: 1, column: 1, scope: !6) |
73 | )" ); |
74 | |
75 | // Convert the module to "new" form debug-info. |
76 | M->convertToNewDbgValues(); |
77 | // Fetch the entry block. |
78 | BasicBlock &BB = M->getFunction(Name: "f" )->getEntryBlock(); |
79 | |
80 | Instruction *Inst1 = &*BB.begin(); |
81 | Instruction *Inst2 = &*std::next(x: BB.begin()); |
82 | Instruction *RetInst = &*std::next(x: Inst2->getIterator()); |
83 | EXPECT_TRUE(Inst1->hasDbgRecords()); |
84 | EXPECT_TRUE(Inst2->hasDbgRecords()); |
85 | EXPECT_FALSE(RetInst->hasDbgRecords()); |
86 | |
87 | // If we move Inst2 to be after Inst1, then it comes _immediately_ after. Were |
88 | // we in dbg.value form we would then have: |
89 | // dbg.value |
90 | // %b = add |
91 | // %c = add |
92 | // dbg.value |
93 | // Check that this is replicated by DbgVariableRecords. |
94 | Inst2->moveAfter(MovePos: Inst1); |
95 | |
96 | // Inst1 should only have one DbgVariableRecord on it. |
97 | EXPECT_TRUE(Inst1->hasDbgRecords()); |
98 | auto Range1 = Inst1->getDbgRecordRange(); |
99 | EXPECT_EQ(std::distance(Range1.begin(), Range1.end()), 1u); |
100 | // Inst2 should have none. |
101 | EXPECT_FALSE(Inst2->hasDbgRecords()); |
102 | // While the return inst should now have one on it. |
103 | EXPECT_TRUE(RetInst->hasDbgRecords()); |
104 | auto Range2 = RetInst->getDbgRecordRange(); |
105 | EXPECT_EQ(std::distance(Range2.begin(), Range2.end()), 1u); |
106 | |
107 | M->convertFromNewDbgValues(); |
108 | |
109 | UseNewDbgInfoFormat = false; |
110 | } |
111 | |
112 | TEST(BasicBlockDbgInfoTest, MarkerOperations) { |
113 | LLVMContext C; |
114 | UseNewDbgInfoFormat = true; |
115 | |
116 | std::unique_ptr<Module> M = parseIR(C, IR: R"( |
117 | define i16 @f(i16 %a) !dbg !6 { |
118 | call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11 |
119 | %b = add i16 %a, 1, !dbg !11 |
120 | call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11 |
121 | ret i16 0, !dbg !11 |
122 | } |
123 | declare void @llvm.dbg.value(metadata, metadata, metadata) #0 |
124 | attributes #0 = { nounwind readnone speculatable willreturn } |
125 | |
126 | !llvm.dbg.cu = !{!0} |
127 | !llvm.module.flags = !{!5} |
128 | |
129 | !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) |
130 | !1 = !DIFile(filename: "t.ll", directory: "/") |
131 | !2 = !{} |
132 | !5 = !{i32 2, !"Debug Info Version", i32 3} |
133 | !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) |
134 | !7 = !DISubroutineType(types: !2) |
135 | !8 = !{!9} |
136 | !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) |
137 | !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned) |
138 | !11 = !DILocation(line: 1, column: 1, scope: !6) |
139 | )" ); |
140 | |
141 | // Fetch the entry block, |
142 | BasicBlock &BB = M->getFunction(Name: "f" )->getEntryBlock(); |
143 | // Convert the module to "new" form debug-info. |
144 | M->convertToNewDbgValues(); |
145 | EXPECT_EQ(BB.size(), 2u); |
146 | |
147 | // Fetch out our two markers, |
148 | Instruction *Instr1 = &*BB.begin(); |
149 | Instruction *Instr2 = Instr1->getNextNode(); |
150 | DbgMarker *Marker1 = Instr1->DebugMarker; |
151 | DbgMarker *Marker2 = Instr2->DebugMarker; |
152 | // There's no TrailingDbgRecords marker allocated yet. |
153 | DbgMarker *EndMarker = nullptr; |
154 | |
155 | // Check that the "getMarker" utilities operate as expected. |
156 | EXPECT_EQ(BB.getMarker(Instr1->getIterator()), Marker1); |
157 | EXPECT_EQ(BB.getMarker(Instr2->getIterator()), Marker2); |
158 | EXPECT_EQ(BB.getNextMarker(Instr1), Marker2); |
159 | EXPECT_EQ(BB.getNextMarker(Instr2), EndMarker); // Is nullptr. |
160 | |
161 | // There should be two DbgVariableRecords, |
162 | EXPECT_EQ(Marker1->StoredDbgRecords.size(), 1u); |
163 | EXPECT_EQ(Marker2->StoredDbgRecords.size(), 1u); |
164 | |
165 | // Unlink them and try to re-insert them through the basic block. |
166 | DbgRecord *DVR1 = &*Marker1->StoredDbgRecords.begin(); |
167 | DbgRecord *DVR2 = &*Marker2->StoredDbgRecords.begin(); |
168 | DVR1->removeFromParent(); |
169 | DVR2->removeFromParent(); |
170 | EXPECT_TRUE(Marker1->StoredDbgRecords.empty()); |
171 | EXPECT_TRUE(Marker2->StoredDbgRecords.empty()); |
172 | |
173 | // This should appear in Marker1. |
174 | BB.insertDbgRecordBefore(DR: DVR1, Here: BB.begin()); |
175 | EXPECT_EQ(Marker1->StoredDbgRecords.size(), 1u); |
176 | EXPECT_EQ(DVR1, &*Marker1->StoredDbgRecords.begin()); |
177 | |
178 | // This should attach to Marker2. |
179 | BB.insertDbgRecordAfter(DR: DVR2, I: &*BB.begin()); |
180 | EXPECT_EQ(Marker2->StoredDbgRecords.size(), 1u); |
181 | EXPECT_EQ(DVR2, &*Marker2->StoredDbgRecords.begin()); |
182 | |
183 | // Now, how about removing instructions? That should cause any |
184 | // DbgVariableRecords to "fall down". |
185 | Instr1->removeFromParent(); |
186 | Marker1 = nullptr; |
187 | // DbgVariableRecords should now be in Marker2. |
188 | EXPECT_EQ(BB.size(), 1u); |
189 | EXPECT_EQ(Marker2->StoredDbgRecords.size(), 2u); |
190 | // They should also be in the correct order. |
191 | SmallVector<DbgRecord *, 2> DVRs; |
192 | for (DbgRecord &DVR : Marker2->getDbgRecordRange()) |
193 | DVRs.push_back(Elt: &DVR); |
194 | EXPECT_EQ(DVRs[0], DVR1); |
195 | EXPECT_EQ(DVRs[1], DVR2); |
196 | |
197 | // If we remove the end instruction, the DbgVariableRecords should fall down |
198 | // into the trailing marker. |
199 | EXPECT_EQ(BB.getTrailingDbgRecords(), nullptr); |
200 | Instr2->removeFromParent(); |
201 | EXPECT_TRUE(BB.empty()); |
202 | EndMarker = BB.getTrailingDbgRecords(); |
203 | ASSERT_NE(EndMarker, nullptr); |
204 | EXPECT_EQ(EndMarker->StoredDbgRecords.size(), 2u); |
205 | // Again, these should arrive in the correct order. |
206 | |
207 | DVRs.clear(); |
208 | for (DbgRecord &DVR : EndMarker->getDbgRecordRange()) |
209 | DVRs.push_back(Elt: &DVR); |
210 | EXPECT_EQ(DVRs[0], DVR1); |
211 | EXPECT_EQ(DVRs[1], DVR2); |
212 | |
213 | // Inserting a normal instruction at the beginning: shouldn't dislodge the |
214 | // DbgVariableRecords. It's intended to not go at the start. |
215 | Instr1->insertBefore(BB, InsertPos: BB.begin()); |
216 | EXPECT_EQ(EndMarker->StoredDbgRecords.size(), 2u); |
217 | Instr1->removeFromParent(); |
218 | |
219 | // Inserting at end(): should dislodge the DbgVariableRecords, if they were |
220 | // dbg.values then they would sit "above" the new instruction. |
221 | Instr1->insertBefore(BB, InsertPos: BB.end()); |
222 | EXPECT_EQ(Instr1->DebugMarker->StoredDbgRecords.size(), 2u); |
223 | // We should de-allocate the trailing marker when something is inserted |
224 | // at end(). |
225 | EXPECT_EQ(BB.getTrailingDbgRecords(), nullptr); |
226 | |
227 | // Remove Instr1: now the DbgVariableRecords will fall down again, |
228 | Instr1->removeFromParent(); |
229 | EndMarker = BB.getTrailingDbgRecords(); |
230 | EXPECT_EQ(EndMarker->StoredDbgRecords.size(), 2u); |
231 | |
232 | // Inserting a terminator, however it's intended, should dislodge the |
233 | // trailing DbgVariableRecords, as it's the clear intention of the caller that |
234 | // this be the final instr in the block, and DbgVariableRecords aren't allowed |
235 | // to live off the end forever. |
236 | Instr2->insertBefore(BB, InsertPos: BB.begin()); |
237 | EXPECT_EQ(Instr2->DebugMarker->StoredDbgRecords.size(), 2u); |
238 | EXPECT_EQ(BB.getTrailingDbgRecords(), nullptr); |
239 | |
240 | // Teardown, |
241 | Instr1->insertBefore(BB, InsertPos: BB.begin()); |
242 | |
243 | UseNewDbgInfoFormat = false; |
244 | } |
245 | |
246 | TEST(BasicBlockDbgInfoTest, HeadBitOperations) { |
247 | LLVMContext C; |
248 | UseNewDbgInfoFormat = true; |
249 | |
250 | std::unique_ptr<Module> M = parseIR(C, IR: R"( |
251 | define i16 @f(i16 %a) !dbg !6 { |
252 | %b = add i16 %a, 1, !dbg !11 |
253 | call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11 |
254 | %c = add i16 %a, 1, !dbg !11 |
255 | %d = add i16 %a, 1, !dbg !11 |
256 | ret i16 0, !dbg !11 |
257 | } |
258 | declare void @llvm.dbg.value(metadata, metadata, metadata) #0 |
259 | attributes #0 = { nounwind readnone speculatable willreturn } |
260 | |
261 | !llvm.dbg.cu = !{!0} |
262 | !llvm.module.flags = !{!5} |
263 | |
264 | !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) |
265 | !1 = !DIFile(filename: "t.ll", directory: "/") |
266 | !2 = !{} |
267 | !5 = !{i32 2, !"Debug Info Version", i32 3} |
268 | !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) |
269 | !7 = !DISubroutineType(types: !2) |
270 | !8 = !{!9} |
271 | !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) |
272 | !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned) |
273 | !11 = !DILocation(line: 1, column: 1, scope: !6) |
274 | )" ); |
275 | |
276 | // Test that the movement of debug-data when using moveBefore etc and |
277 | // insertBefore etc are governed by the "head" bit of iterators. |
278 | BasicBlock &BB = M->getFunction(Name: "f" )->getEntryBlock(); |
279 | // Convert the module to "new" form debug-info. |
280 | M->convertToNewDbgValues(); |
281 | |
282 | // Test that the head bit behaves as expected: it should be set when the |
283 | // code wants the _start_ of the block, but not otherwise. |
284 | EXPECT_TRUE(BB.getFirstInsertionPt().getHeadBit()); |
285 | BasicBlock::iterator BeginIt = BB.begin(); |
286 | EXPECT_TRUE(BeginIt.getHeadBit()); |
287 | // If you launder the instruction pointer through dereferencing and then |
288 | // get the iterator again with getIterator, the head bit is lost. This is |
289 | // deliberate: if you're calling getIterator, then you're requesting an |
290 | // iterator for the position of _this_ instruction, not "the start of this |
291 | // block". |
292 | BasicBlock::iterator BeginIt2 = BeginIt->getIterator(); |
293 | EXPECT_FALSE(BeginIt2.getHeadBit()); |
294 | |
295 | // Fetch some instruction pointers. |
296 | Instruction *BInst = &*BeginIt; |
297 | Instruction *CInst = BInst->getNextNode(); |
298 | Instruction *DInst = CInst->getNextNode(); |
299 | // CInst should have debug-info. |
300 | ASSERT_TRUE(CInst->DebugMarker); |
301 | EXPECT_FALSE(CInst->DebugMarker->StoredDbgRecords.empty()); |
302 | |
303 | // If we move "c" to the start of the block, just normally, then the |
304 | // DbgVariableRecords should fall down to "d". |
305 | CInst->moveBefore(BB, I: BeginIt2); |
306 | EXPECT_TRUE(!CInst->DebugMarker || |
307 | CInst->DebugMarker->StoredDbgRecords.empty()); |
308 | ASSERT_TRUE(DInst->DebugMarker); |
309 | EXPECT_FALSE(DInst->DebugMarker->StoredDbgRecords.empty()); |
310 | |
311 | // Wheras if we move D to the start of the block with moveBeforePreserving, |
312 | // the DbgVariableRecords should move with it. |
313 | DInst->moveBeforePreserving(BB, I: BB.begin()); |
314 | EXPECT_FALSE(DInst->DebugMarker->StoredDbgRecords.empty()); |
315 | EXPECT_EQ(&*BB.begin(), DInst); |
316 | |
317 | // Similarly, moveAfterPreserving "D" to "C" should move DbgVariableRecords |
318 | // with "D". |
319 | DInst->moveAfterPreserving(MovePos: CInst); |
320 | EXPECT_FALSE(DInst->DebugMarker->StoredDbgRecords.empty()); |
321 | |
322 | // (move back to the start...) |
323 | DInst->moveBeforePreserving(BB, I: BB.begin()); |
324 | |
325 | // Current order of insts: "D -> C -> B -> Ret". DbgVariableRecords on "D". |
326 | // If we move "C" to the beginning of the block, it should go before the |
327 | // DbgVariableRecords. They'll stay on "D". |
328 | CInst->moveBefore(BB, I: BB.begin()); |
329 | EXPECT_TRUE(!CInst->DebugMarker || |
330 | CInst->DebugMarker->StoredDbgRecords.empty()); |
331 | EXPECT_FALSE(DInst->DebugMarker->StoredDbgRecords.empty()); |
332 | EXPECT_EQ(&*BB.begin(), CInst); |
333 | EXPECT_EQ(CInst->getNextNode(), DInst); |
334 | |
335 | // Move back. |
336 | CInst->moveBefore(MovePos: BInst); |
337 | EXPECT_EQ(&*BB.begin(), DInst); |
338 | |
339 | // Current order of insts: "D -> C -> B -> Ret". DbgVariableRecords on "D". |
340 | // Now move CInst to the position of DInst, but using getIterator instead of |
341 | // BasicBlock::begin. This signals that we want the "C" instruction to be |
342 | // immediately before "D", with any DbgVariableRecords on "D" now moving to |
343 | // "C". It's the equivalent of moving an instruction to the position between a |
344 | // run of dbg.values and the next instruction. |
345 | CInst->moveBefore(BB, I: DInst->getIterator()); |
346 | // CInst gains the DbgVariableRecords. |
347 | EXPECT_TRUE(!DInst->DebugMarker || |
348 | DInst->DebugMarker->StoredDbgRecords.empty()); |
349 | EXPECT_FALSE(CInst->DebugMarker->StoredDbgRecords.empty()); |
350 | EXPECT_EQ(&*BB.begin(), CInst); |
351 | |
352 | UseNewDbgInfoFormat = false; |
353 | } |
354 | |
355 | TEST(BasicBlockDbgInfoTest, InstrDbgAccess) { |
356 | LLVMContext C; |
357 | UseNewDbgInfoFormat = true; |
358 | |
359 | std::unique_ptr<Module> M = parseIR(C, IR: R"( |
360 | define i16 @f(i16 %a) !dbg !6 { |
361 | %b = add i16 %a, 1, !dbg !11 |
362 | call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11 |
363 | %c = add i16 %a, 1, !dbg !11 |
364 | %d = add i16 %a, 1, !dbg !11 |
365 | ret i16 0, !dbg !11 |
366 | } |
367 | declare void @llvm.dbg.value(metadata, metadata, metadata) #0 |
368 | attributes #0 = { nounwind readnone speculatable willreturn } |
369 | |
370 | !llvm.dbg.cu = !{!0} |
371 | !llvm.module.flags = !{!5} |
372 | |
373 | !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) |
374 | !1 = !DIFile(filename: "t.ll", directory: "/") |
375 | !2 = !{} |
376 | !5 = !{i32 2, !"Debug Info Version", i32 3} |
377 | !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) |
378 | !7 = !DISubroutineType(types: !2) |
379 | !8 = !{!9} |
380 | !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) |
381 | !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned) |
382 | !11 = !DILocation(line: 1, column: 1, scope: !6) |
383 | )" ); |
384 | |
385 | // Check that DbgVariableRecords can be accessed from Instructions without |
386 | // digging into the depths of DbgMarkers. |
387 | BasicBlock &BB = M->getFunction(Name: "f" )->getEntryBlock(); |
388 | // Convert the module to "new" form debug-info. |
389 | M->convertToNewDbgValues(); |
390 | |
391 | Instruction *BInst = &*BB.begin(); |
392 | Instruction *CInst = BInst->getNextNode(); |
393 | Instruction *DInst = CInst->getNextNode(); |
394 | |
395 | ASSERT_FALSE(BInst->DebugMarker); |
396 | ASSERT_TRUE(CInst->DebugMarker); |
397 | ASSERT_EQ(CInst->DebugMarker->StoredDbgRecords.size(), 1u); |
398 | DbgRecord *DVR1 = &*CInst->DebugMarker->StoredDbgRecords.begin(); |
399 | ASSERT_TRUE(DVR1); |
400 | EXPECT_FALSE(BInst->hasDbgRecords()); |
401 | |
402 | // Clone DbgVariableRecords from one inst to another. Other arguments to clone |
403 | // are tested in DbgMarker test. |
404 | auto Range1 = BInst->cloneDebugInfoFrom(From: CInst); |
405 | EXPECT_EQ(BInst->DebugMarker->StoredDbgRecords.size(), 1u); |
406 | DbgRecord *DVR2 = &*BInst->DebugMarker->StoredDbgRecords.begin(); |
407 | EXPECT_EQ(std::distance(Range1.begin(), Range1.end()), 1u); |
408 | EXPECT_EQ(&*Range1.begin(), DVR2); |
409 | EXPECT_NE(DVR1, DVR2); |
410 | |
411 | // We should be able to get a range over exactly the same information. |
412 | auto Range2 = BInst->getDbgRecordRange(); |
413 | EXPECT_EQ(Range1.begin(), Range2.begin()); |
414 | EXPECT_EQ(Range1.end(), Range2.end()); |
415 | |
416 | // We should be able to query if there are DbgVariableRecords, |
417 | EXPECT_TRUE(BInst->hasDbgRecords()); |
418 | EXPECT_TRUE(CInst->hasDbgRecords()); |
419 | EXPECT_FALSE(DInst->hasDbgRecords()); |
420 | |
421 | // Dropping should be easy, |
422 | BInst->dropDbgRecords(); |
423 | EXPECT_FALSE(BInst->hasDbgRecords()); |
424 | EXPECT_EQ(BInst->DebugMarker->StoredDbgRecords.size(), 0u); |
425 | |
426 | // And we should be able to drop individual DbgVariableRecords. |
427 | CInst->dropOneDbgRecord(I: DVR1); |
428 | EXPECT_FALSE(CInst->hasDbgRecords()); |
429 | EXPECT_EQ(CInst->DebugMarker->StoredDbgRecords.size(), 0u); |
430 | |
431 | UseNewDbgInfoFormat = false; |
432 | } |
433 | |
434 | /* Let's recall the big illustration from BasicBlock::spliceDebugInfo: |
435 | |
436 | Dest |
437 | | |
438 | this-block: A----A----A ====A----A----A----A---A---A |
439 | Src-block ++++B---B---B---B:::C |
440 | | | |
441 | First Last |
442 | |
443 | in all it's glory. Depending on the bit-configurations for the iterator head |
444 | / tail bits on the three named iterators, there are eight ways for a splice to |
445 | occur. To save the amount of thinking needed to pack this into one unit test, |
446 | just test the same IR eight times with difference splices. The IR shall be |
447 | thus: |
448 | |
449 | define i16 @f(i16 %a) !dbg !6 { |
450 | entry: |
451 | call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11 |
452 | %b = add i16 %a, 1, !dbg !11 |
453 | call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11 |
454 | br label %exit, !dbg !11 |
455 | |
456 | exit: |
457 | call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11 |
458 | %c = add i16 %b, 1, !dbg !11 |
459 | ret i16 0, !dbg !11 |
460 | } |
461 | |
462 | The iterators will be: |
463 | Dest: exit block, "c" instruction. |
464 | First: entry block, "b" instruction. |
465 | Last: entry block, branch instruction. |
466 | |
467 | The numbered configurations will be: |
468 | |
469 | | Dest-Head | First-Head | Last-tail |
470 | ----+----------------+----------------+------------ |
471 | 0 | false | false | false |
472 | 1 | true | false | false |
473 | 2 | false | true | false |
474 | 3 | true | true | false |
475 | 4 | false | false | true |
476 | 5 | true | false | true |
477 | 6 | false | true | true |
478 | 7 | true | true | true |
479 | |
480 | Each numbered test scenario will also have a short explanation indicating what |
481 | this bit configuration represents. |
482 | */ |
483 | |
484 | static const std::string SpliceTestIR = R"( |
485 | define i16 @f(i16 %a) !dbg !6 { |
486 | call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11 |
487 | %b = add i16 %a, 1, !dbg !11 |
488 | call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11 |
489 | br label %exit, !dbg !11 |
490 | |
491 | exit: |
492 | call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11 |
493 | %c = add i16 %b, 1, !dbg !11 |
494 | ret i16 0, !dbg !11 |
495 | } |
496 | declare void @llvm.dbg.value(metadata, metadata, metadata) #0 |
497 | attributes #0 = { nounwind readnone speculatable willreturn } |
498 | |
499 | !llvm.dbg.cu = !{!0} |
500 | !llvm.module.flags = !{!5} |
501 | |
502 | !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) |
503 | !1 = !DIFile(filename: "t.ll", directory: "/") |
504 | !2 = !{} |
505 | !5 = !{i32 2, !"Debug Info Version", i32 3} |
506 | !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) |
507 | !7 = !DISubroutineType(types: !2) |
508 | !8 = !{!9} |
509 | !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) |
510 | !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned) |
511 | !11 = !DILocation(line: 1, column: 1, scope: !6) |
512 | )" ; |
513 | |
514 | class DbgSpliceTest : public ::testing::Test { |
515 | protected: |
516 | LLVMContext C; |
517 | std::unique_ptr<Module> M; |
518 | BasicBlock *BBEntry, *BBExit; |
519 | BasicBlock::iterator Dest, First, Last; |
520 | Instruction *BInst, *Branch, *CInst; |
521 | DbgVariableRecord *DVRA, *DVRB, *DVRConst; |
522 | |
523 | void SetUp() override { |
524 | UseNewDbgInfoFormat = true; |
525 | M = parseIR(C, IR: SpliceTestIR.c_str()); |
526 | M->convertToNewDbgValues(); |
527 | |
528 | BBEntry = &M->getFunction(Name: "f" )->getEntryBlock(); |
529 | BBExit = BBEntry->getNextNode(); |
530 | |
531 | Dest = BBExit->begin(); |
532 | First = BBEntry->begin(); |
533 | Last = BBEntry->getTerminator()->getIterator(); |
534 | BInst = &*First; |
535 | Branch = &*Last; |
536 | CInst = &*Dest; |
537 | |
538 | DVRA = |
539 | cast<DbgVariableRecord>(Val: &*BInst->DebugMarker->StoredDbgRecords.begin()); |
540 | DVRB = cast<DbgVariableRecord>( |
541 | Val: &*Branch->DebugMarker->StoredDbgRecords.begin()); |
542 | DVRConst = |
543 | cast<DbgVariableRecord>(Val: &*CInst->DebugMarker->StoredDbgRecords.begin()); |
544 | } |
545 | |
546 | void TearDown() override { UseNewDbgInfoFormat = false; } |
547 | |
548 | bool InstContainsDbgVariableRecord(Instruction *I, DbgVariableRecord *DVR) { |
549 | for (DbgRecord &D : I->getDbgRecordRange()) { |
550 | if (&D == DVR) { |
551 | // Confirm too that the links between the records are correct. |
552 | EXPECT_EQ(DVR->Marker, I->DebugMarker); |
553 | EXPECT_EQ(I->DebugMarker->MarkedInstr, I); |
554 | return true; |
555 | } |
556 | } |
557 | return false; |
558 | } |
559 | |
560 | bool CheckDVROrder(Instruction *I, |
561 | SmallVector<DbgVariableRecord *> CheckVals) { |
562 | SmallVector<DbgRecord *> Vals; |
563 | for (DbgRecord &D : I->getDbgRecordRange()) |
564 | Vals.push_back(Elt: &D); |
565 | |
566 | EXPECT_EQ(Vals.size(), CheckVals.size()); |
567 | if (Vals.size() != CheckVals.size()) |
568 | return false; |
569 | |
570 | for (unsigned int I = 0; I < Vals.size(); ++I) { |
571 | EXPECT_EQ(Vals[I], CheckVals[I]); |
572 | // Provide another expectation failure to let us localise what goes wrong, |
573 | // by returning a flag to the caller. |
574 | if (Vals[I] != CheckVals[I]) |
575 | return false; |
576 | } |
577 | return true; |
578 | } |
579 | }; |
580 | |
581 | TEST_F(DbgSpliceTest, DbgSpliceTest0) { |
582 | Dest.setHeadBit(false); |
583 | First.setHeadBit(false); |
584 | Last.setTailBit(false); |
585 | |
586 | /* |
587 | define i16 @f(i16 %a) !dbg !6 { |
588 | BBEntry entry: |
589 | DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata |
590 | !DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call |
591 | void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), |
592 | !dbg !11 Last br label %exit, !dbg !11 |
593 | |
594 | BBExit exit: |
595 | DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata |
596 | !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0, |
597 | !dbg !11 |
598 | } |
599 | |
600 | Splice from First, not including leading dbg.value, to Last, including the |
601 | trailing dbg.value. Place at Dest, between the constant dbg.value and %c. |
602 | %b, and the following dbg.value, should move, to: |
603 | |
604 | define i16 @f(i16 %a) !dbg !6 { |
605 | BBEntry entry: |
606 | DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata |
607 | !DIExpression()), !dbg !11 Last br label %exit, !dbg !11 |
608 | |
609 | BBExit exit: |
610 | DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata |
611 | !DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call |
612 | void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), |
613 | !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0, !dbg !11 |
614 | } |
615 | |
616 | |
617 | */ |
618 | BBExit->splice(ToIt: Dest, FromBB: BBEntry, FromBeginIt: First, FromEndIt: Last); |
619 | EXPECT_EQ(BInst->getParent(), BBExit); |
620 | EXPECT_EQ(CInst->getParent(), BBExit); |
621 | EXPECT_EQ(Branch->getParent(), BBEntry); |
622 | |
623 | // DVRB: should be on Dest, in exit block. |
624 | EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRB)); |
625 | |
626 | // DVRA, should have "fallen" onto the branch, remained in entry block. |
627 | EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRA)); |
628 | |
629 | // DVRConst should be on the moved %b instruction. |
630 | EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRConst)); |
631 | } |
632 | |
633 | TEST_F(DbgSpliceTest, DbgSpliceTest1) { |
634 | Dest.setHeadBit(true); |
635 | First.setHeadBit(false); |
636 | Last.setTailBit(false); |
637 | |
638 | /* |
639 | define i16 @f(i16 %a) !dbg !6 { |
640 | BBEntry entry: |
641 | DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata |
642 | !DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call |
643 | void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), |
644 | !dbg !11 Last br label %exit, !dbg !11 |
645 | |
646 | BBExit exit: |
647 | DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata |
648 | !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0, |
649 | !dbg !11 |
650 | } |
651 | |
652 | Splice from First, not including leading dbg.value, to Last, including the |
653 | trailing dbg.value. Place at the head of Dest, i.e. at the very start of |
654 | BBExit, before any debug-info there. Becomes: |
655 | |
656 | define i16 @f(i16 %a) !dbg !6 { |
657 | BBEntry entry: |
658 | DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata |
659 | !DIExpression()), !dbg !11 Last br label %exit, !dbg !11 |
660 | |
661 | BBExit exit: |
662 | First %b = add i16 %a, 1, !dbg !11 |
663 | DVRB call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata |
664 | !DIExpression()), !dbg !11 DVRConst call void @llvm.dbg.value(metadata i16 0, |
665 | metadata !9, metadata !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, |
666 | !dbg !11 ret i16 0, !dbg !11 |
667 | } |
668 | |
669 | |
670 | */ |
671 | BBExit->splice(ToIt: Dest, FromBB: BBEntry, FromBeginIt: First, FromEndIt: Last); |
672 | EXPECT_EQ(BInst->getParent(), BBExit); |
673 | EXPECT_EQ(CInst->getParent(), BBExit); |
674 | EXPECT_EQ(Branch->getParent(), BBEntry); |
675 | |
676 | // DVRB: should be on CInst, in exit block. |
677 | EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRB)); |
678 | |
679 | // DVRA, should have "fallen" onto the branch, remained in entry block. |
680 | EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRA)); |
681 | |
682 | // DVRConst should be behind / after the moved instructions, remain on CInst. |
683 | EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRConst)); |
684 | |
685 | // Order of DVRB and DVRConst should be thus: |
686 | EXPECT_TRUE(CheckDVROrder(CInst, {DVRB, DVRConst})); |
687 | } |
688 | |
689 | TEST_F(DbgSpliceTest, DbgSpliceTest2) { |
690 | Dest.setHeadBit(false); |
691 | First.setHeadBit(true); |
692 | Last.setTailBit(false); |
693 | |
694 | /* |
695 | define i16 @f(i16 %a) !dbg !6 { |
696 | BBEntry entry: |
697 | DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata |
698 | !DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call |
699 | void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), |
700 | !dbg !11 Last br label %exit, !dbg !11 |
701 | |
702 | BBExit exit: |
703 | DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata |
704 | !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0, |
705 | !dbg !11 |
706 | } |
707 | |
708 | Splice from head of First, which includes the leading dbg.value, to Last, |
709 | including the trailing dbg.value. Place in front of Dest, but after any |
710 | debug-info there. Becomes: |
711 | |
712 | define i16 @f(i16 %a) !dbg !6 { |
713 | BBEntry entry: |
714 | Last br label %exit, !dbg !11 |
715 | |
716 | BBExit exit: |
717 | DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata |
718 | !DIExpression()), !dbg !11 DVRA call void @llvm.dbg.value(metadata i16 %a, |
719 | metadata !9, metadata !DIExpression()), !dbg !11 First %b = add i16 %a, 1, |
720 | !dbg !11 DVRB call void @llvm.dbg.value(metadata i16 %b, metadata !9, |
721 | metadata !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret |
722 | i16 0, !dbg !11 |
723 | } |
724 | |
725 | |
726 | */ |
727 | BBExit->splice(ToIt: Dest, FromBB: BBEntry, FromBeginIt: First, FromEndIt: Last); |
728 | EXPECT_EQ(BInst->getParent(), BBExit); |
729 | EXPECT_EQ(CInst->getParent(), BBExit); |
730 | |
731 | // DVRB: should be on CInst, in exit block. |
732 | EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRB)); |
733 | |
734 | // DVRA, should have transferred with the spliced instructions, remains on |
735 | // the "b" inst. |
736 | EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRA)); |
737 | |
738 | // DVRConst should be ahead of the moved instructions, ahead of BInst. |
739 | EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRConst)); |
740 | |
741 | // Order of DVRA and DVRConst should be thus: |
742 | EXPECT_TRUE(CheckDVROrder(BInst, {DVRConst, DVRA})); |
743 | } |
744 | |
745 | TEST_F(DbgSpliceTest, DbgSpliceTest3) { |
746 | Dest.setHeadBit(true); |
747 | First.setHeadBit(true); |
748 | Last.setTailBit(false); |
749 | |
750 | /* |
751 | define i16 @f(i16 %a) !dbg !6 { |
752 | BBEntry entry: |
753 | DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata |
754 | !DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call |
755 | void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), |
756 | !dbg !11 Last br label %exit, !dbg !11 |
757 | |
758 | BBExit exit: |
759 | DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata |
760 | !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0, |
761 | !dbg !11 |
762 | } |
763 | |
764 | Splice from head of First, which includes the leading dbg.value, to Last, |
765 | including the trailing dbg.value. Place at head of Dest, before any |
766 | debug-info there. Becomes: |
767 | |
768 | define i16 @f(i16 %a) !dbg !6 { |
769 | BBEntry entry: |
770 | Last br label %exit, !dbg !11 |
771 | |
772 | BBExit exit: |
773 | DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata |
774 | !DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call |
775 | void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), |
776 | !dbg !11 DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, |
777 | metadata !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret |
778 | i16 0, !dbg !11 |
779 | } |
780 | |
781 | */ |
782 | BBExit->splice(ToIt: Dest, FromBB: BBEntry, FromBeginIt: First, FromEndIt: Last); |
783 | EXPECT_EQ(BInst->getParent(), BBExit); |
784 | EXPECT_EQ(CInst->getParent(), BBExit); |
785 | |
786 | // DVRB: should be on CInst, in exit block. |
787 | EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRB)); |
788 | |
789 | // DVRA, should have transferred with the spliced instructions, remains on |
790 | // the "b" inst. |
791 | EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRA)); |
792 | |
793 | // DVRConst should be behind the moved instructions, ahead of CInst. |
794 | EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRConst)); |
795 | |
796 | // Order of DVRB and DVRConst should be thus: |
797 | EXPECT_TRUE(CheckDVROrder(CInst, {DVRB, DVRConst})); |
798 | } |
799 | |
800 | TEST_F(DbgSpliceTest, DbgSpliceTest4) { |
801 | Dest.setHeadBit(false); |
802 | First.setHeadBit(false); |
803 | Last.setTailBit(true); |
804 | |
805 | /* |
806 | define i16 @f(i16 %a) !dbg !6 { |
807 | BBEntry entry: |
808 | DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata |
809 | !DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call |
810 | void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), |
811 | !dbg !11 Last br label %exit, !dbg !11 |
812 | |
813 | BBExit exit: |
814 | DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata |
815 | !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0, |
816 | !dbg !11 |
817 | } |
818 | |
819 | Splice from First, not including the leading dbg.value, to Last, but NOT |
820 | including the trailing dbg.value because the tail bit is set. Place at Dest, |
821 | after any debug-info there. Becomes: |
822 | |
823 | define i16 @f(i16 %a) !dbg !6 { |
824 | BBEntry entry: |
825 | DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata |
826 | !DIExpression()), !dbg !11 DVRB call void @llvm.dbg.value(metadata i16 %b, |
827 | metadata !9, metadata !DIExpression()), !dbg !11 Last br label %exit, !dbg |
828 | !11 |
829 | |
830 | BBExit exit: |
831 | DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata |
832 | !DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 Dest %c = |
833 | add i16 %b, 1, !dbg !11 ret i16 0, !dbg !11 |
834 | } |
835 | |
836 | */ |
837 | BBExit->splice(ToIt: Dest, FromBB: BBEntry, FromBeginIt: First, FromEndIt: Last); |
838 | EXPECT_EQ(BInst->getParent(), BBExit); |
839 | EXPECT_EQ(CInst->getParent(), BBExit); |
840 | EXPECT_EQ(Branch->getParent(), BBEntry); |
841 | |
842 | // DVRB: should be on Branch as before, remain in entry block. |
843 | EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRB)); |
844 | |
845 | // DVRA, should have remained in entry block, falls onto Branch inst. |
846 | EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRA)); |
847 | |
848 | // DVRConst should be ahead of the moved instructions, BInst. |
849 | EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRConst)); |
850 | |
851 | // Order of DVRA and DVRA should be thus: |
852 | EXPECT_TRUE(CheckDVROrder(Branch, {DVRA, DVRB})); |
853 | } |
854 | |
855 | TEST_F(DbgSpliceTest, DbgSpliceTest5) { |
856 | Dest.setHeadBit(true); |
857 | First.setHeadBit(false); |
858 | Last.setTailBit(true); |
859 | |
860 | /* |
861 | define i16 @f(i16 %a) !dbg !6 { |
862 | BBEntry entry: |
863 | DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata |
864 | !DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call |
865 | void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), |
866 | !dbg !11 Last br label %exit, !dbg !11 |
867 | |
868 | BBExit exit: |
869 | DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata |
870 | !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0, |
871 | !dbg !11 |
872 | } |
873 | |
874 | Splice from First, not including the leading dbg.value, to Last, but NOT |
875 | including the trailing dbg.value because the tail bit is set. Place at head |
876 | of Dest, before any debug-info there. Becomes: |
877 | |
878 | define i16 @f(i16 %a) !dbg !6 { |
879 | BBEntry entry: |
880 | DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata |
881 | !DIExpression()), !dbg !11 DVRB call void @llvm.dbg.value(metadata i16 %b, |
882 | metadata !9, metadata !DIExpression()), !dbg !11 Last br label %exit, !dbg |
883 | !11 |
884 | |
885 | BBExit exit: |
886 | First %b = add i16 %a, 1, !dbg !11 |
887 | DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata |
888 | !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0, |
889 | !dbg !11 |
890 | } |
891 | |
892 | */ |
893 | BBExit->splice(ToIt: Dest, FromBB: BBEntry, FromBeginIt: First, FromEndIt: Last); |
894 | EXPECT_EQ(BInst->getParent(), BBExit); |
895 | EXPECT_EQ(CInst->getParent(), BBExit); |
896 | EXPECT_EQ(Branch->getParent(), BBEntry); |
897 | |
898 | // DVRB: should be on Branch as before, remain in entry block. |
899 | EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRB)); |
900 | |
901 | // DVRA, should have remained in entry block, falls onto Branch inst. |
902 | EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRA)); |
903 | |
904 | // DVRConst should be behind of the moved instructions, on CInst. |
905 | EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRConst)); |
906 | |
907 | // Order of DVRA and DVRB should be thus: |
908 | EXPECT_TRUE(CheckDVROrder(Branch, {DVRA, DVRB})); |
909 | } |
910 | |
911 | TEST_F(DbgSpliceTest, DbgSpliceTest6) { |
912 | Dest.setHeadBit(false); |
913 | First.setHeadBit(true); |
914 | Last.setTailBit(true); |
915 | |
916 | /* |
917 | define i16 @f(i16 %a) !dbg !6 { |
918 | BBEntry entry: |
919 | DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata |
920 | !DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call |
921 | void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), |
922 | !dbg !11 Last br label %exit, !dbg !11 |
923 | |
924 | BBExit exit: |
925 | DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata |
926 | !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0, |
927 | !dbg !11 |
928 | } |
929 | |
930 | Splice from First, including the leading dbg.value, to Last, but NOT |
931 | including the trailing dbg.value because the tail bit is set. Place at Dest, |
932 | after any debug-info there. Becomes: |
933 | |
934 | define i16 @f(i16 %a) !dbg !6 { |
935 | BBEntry entry: |
936 | DVRB call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata |
937 | !DIExpression()), !dbg !11 Last br label %exit, !dbg !11 |
938 | |
939 | BBExit exit: |
940 | DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata |
941 | !DIExpression()), !dbg !11 DVRA call void @llvm.dbg.value(metadata i16 %a, |
942 | metadata !9, metadata !DIExpression()), !dbg !11 First %b = add i16 %a, 1, |
943 | !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0, !dbg !11 |
944 | } |
945 | |
946 | */ |
947 | BBExit->splice(ToIt: Dest, FromBB: BBEntry, FromBeginIt: First, FromEndIt: Last); |
948 | EXPECT_EQ(BInst->getParent(), BBExit); |
949 | EXPECT_EQ(CInst->getParent(), BBExit); |
950 | EXPECT_EQ(Branch->getParent(), BBEntry); |
951 | |
952 | // DVRB: should be on Branch as before, remain in entry block. |
953 | EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRB)); |
954 | |
955 | // DVRA, should have transferred to BBExit, on B inst. |
956 | EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRA)); |
957 | |
958 | // DVRConst should be ahead of the moved instructions, on BInst. |
959 | EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRConst)); |
960 | |
961 | // Order of DVRA and DVRConst should be thus: |
962 | EXPECT_TRUE(CheckDVROrder(BInst, {DVRConst, DVRA})); |
963 | } |
964 | |
965 | TEST_F(DbgSpliceTest, DbgSpliceTest7) { |
966 | Dest.setHeadBit(true); |
967 | First.setHeadBit(true); |
968 | Last.setTailBit(true); |
969 | |
970 | /* |
971 | define i16 @f(i16 %a) !dbg !6 { |
972 | BBEntry entry: |
973 | DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata |
974 | !DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call |
975 | void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), |
976 | !dbg !11 Last br label %exit, !dbg !11 |
977 | |
978 | BBExit exit: |
979 | DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata |
980 | !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0, |
981 | !dbg !11 |
982 | } |
983 | |
984 | Splice from First, including the leading dbg.value, to Last, but NOT |
985 | including the trailing dbg.value because the tail bit is set. Place at head |
986 | of Dest, before any debug-info there. Becomes: |
987 | |
988 | define i16 @f(i16 %a) !dbg !6 { |
989 | BBEntry entry: |
990 | DVRB call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata |
991 | !DIExpression()), !dbg !11 Last br label %exit, !dbg !11 |
992 | |
993 | BBExit exit: |
994 | DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata |
995 | !DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRConst call |
996 | void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), |
997 | !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0, !dbg !11 |
998 | } |
999 | |
1000 | */ |
1001 | BBExit->splice(ToIt: Dest, FromBB: BBEntry, FromBeginIt: First, FromEndIt: Last); |
1002 | EXPECT_EQ(BInst->getParent(), BBExit); |
1003 | EXPECT_EQ(CInst->getParent(), BBExit); |
1004 | EXPECT_EQ(Branch->getParent(), BBEntry); |
1005 | |
1006 | // DVRB: should be on Branch as before, remain in entry block. |
1007 | EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRB)); |
1008 | |
1009 | // DVRA, should have transferred to BBExit, on B inst. |
1010 | EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRA)); |
1011 | |
1012 | // DVRConst should be after of the moved instructions, on CInst. |
1013 | EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRConst)); |
1014 | } |
1015 | |
1016 | // But wait, there's more! What if you splice a range that is empty, but |
1017 | // implicitly contains debug-info? In the dbg.value design for debug-info, |
1018 | // this would be an explicit range, but in DbgVariableRecord debug-info, it |
1019 | // isn't. Check that if we try to do that, with differing head-bit values, that |
1020 | // DbgVariableRecords are transferred. |
1021 | // Test with empty transfers to Dest, with head bit set and not set. |
1022 | |
1023 | TEST_F(DbgSpliceTest, DbgSpliceEmpty0) { |
1024 | Dest.setHeadBit(false); |
1025 | First.setHeadBit(false); |
1026 | Last.setHeadBit(false); |
1027 | /* |
1028 | define i16 @f(i16 %a) !dbg !6 { |
1029 | BBEntry entry: |
1030 | DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata |
1031 | !DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call |
1032 | void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), |
1033 | !dbg !11 Last br label %exit, !dbg !11 |
1034 | |
1035 | BBExit exit: |
1036 | DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata |
1037 | !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0, |
1038 | !dbg !11 |
1039 | } |
1040 | |
1041 | Splice from BBEntry.getFirstInsertionPt to First -- this implicitly is a |
1042 | splice of DVRA, but the iterators are pointing at the same instruction. The |
1043 | only difference is the setting of the head bit. Becomes; |
1044 | |
1045 | define i16 @f(i16 %a) !dbg !6 { |
1046 | First %b = add i16 %a, 1, !dbg !11 |
1047 | DVRB call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata |
1048 | !DIExpression()), !dbg !11 Last br label %exit, !dbg !11 |
1049 | |
1050 | BBExit exit: |
1051 | DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata |
1052 | !DIExpression()), !dbg !11 DVRA call void @llvm.dbg.value(metadata i16 %a, |
1053 | metadata !9, metadata !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, |
1054 | !dbg !11 ret i16 0, !dbg !11 |
1055 | } |
1056 | |
1057 | */ |
1058 | BBExit->splice(ToIt: Dest, FromBB: BBEntry, FromBeginIt: BBEntry->getFirstInsertionPt(), FromEndIt: First); |
1059 | EXPECT_EQ(BInst->getParent(), BBEntry); |
1060 | EXPECT_EQ(CInst->getParent(), BBExit); |
1061 | EXPECT_EQ(Branch->getParent(), BBEntry); |
1062 | |
1063 | // DVRB: should be on Branch as before, remain in entry block. |
1064 | EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRB)); |
1065 | |
1066 | // DVRA, should have transferred to BBExit, on C inst. |
1067 | EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRA)); |
1068 | |
1069 | // DVRConst should be ahead of the moved DbgVariableRecord, on CInst. |
1070 | EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRConst)); |
1071 | |
1072 | // Order of DVRA and DVRConst should be thus: |
1073 | EXPECT_TRUE(CheckDVROrder(CInst, {DVRConst, DVRA})); |
1074 | } |
1075 | |
1076 | TEST_F(DbgSpliceTest, DbgSpliceEmpty1) { |
1077 | Dest.setHeadBit(true); |
1078 | First.setHeadBit(false); |
1079 | Last.setHeadBit(false); |
1080 | /* |
1081 | define i16 @f(i16 %a) !dbg !6 { |
1082 | BBEntry entry: |
1083 | DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata |
1084 | !DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call |
1085 | void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), |
1086 | !dbg !11 Last br label %exit, !dbg !11 |
1087 | |
1088 | BBExit exit: |
1089 | DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata |
1090 | !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0, |
1091 | !dbg !11 |
1092 | } |
1093 | |
1094 | Splice from BBEntry.getFirstInsertionPt to First -- this implicitly is a |
1095 | splice of DVRA, but the iterators are pointing at the same instruction. The |
1096 | only difference is the setting of the head bit. Insert at head of Dest, |
1097 | i.e. before DVRConst. Becomes; |
1098 | |
1099 | define i16 @f(i16 %a) !dbg !6 { |
1100 | First %b = add i16 %a, 1, !dbg !11 |
1101 | DVRB call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata |
1102 | !DIExpression()), !dbg !11 Last br label %exit, !dbg !11 |
1103 | |
1104 | BBExit exit: |
1105 | DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata |
1106 | !DIExpression()), !dbg !11 DVRConst call void @llvm.dbg.value(metadata i16 0, |
1107 | metadata !9, metadata !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, |
1108 | !dbg !11 ret i16 0, !dbg !11 |
1109 | } |
1110 | |
1111 | */ |
1112 | BBExit->splice(ToIt: Dest, FromBB: BBEntry, FromBeginIt: BBEntry->getFirstInsertionPt(), FromEndIt: First); |
1113 | EXPECT_EQ(BInst->getParent(), BBEntry); |
1114 | EXPECT_EQ(CInst->getParent(), BBExit); |
1115 | EXPECT_EQ(Branch->getParent(), BBEntry); |
1116 | |
1117 | // DVRB: should be on Branch as before, remain in entry block. |
1118 | EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRB)); |
1119 | |
1120 | // DVRA, should have transferred to BBExit, on C inst. |
1121 | EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRA)); |
1122 | |
1123 | // DVRConst should be ahead of the moved DbgVariableRecord, on CInst. |
1124 | EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRConst)); |
1125 | |
1126 | // Order of DVRA and DVRConst should be thus: |
1127 | EXPECT_TRUE(CheckDVROrder(CInst, {DVRA, DVRConst})); |
1128 | } |
1129 | |
1130 | // If we splice new instructions into a block with trailing DbgVariableRecords, |
1131 | // then the trailing DbgVariableRecords should get flushed back out. |
1132 | TEST(BasicBlockDbgInfoTest, DbgSpliceTrailing) { |
1133 | LLVMContext C; |
1134 | UseNewDbgInfoFormat = true; |
1135 | |
1136 | std::unique_ptr<Module> M = parseIR(C, IR: R"( |
1137 | define i16 @f(i16 %a) !dbg !6 { |
1138 | entry: |
1139 | call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11 |
1140 | br label %exit |
1141 | |
1142 | exit: |
1143 | %b = add i16 %a, 1, !dbg !11 |
1144 | ret i16 0, !dbg !11 |
1145 | } |
1146 | declare void @llvm.dbg.value(metadata, metadata, metadata) #0 |
1147 | attributes #0 = { nounwind readnone speculatable willreturn } |
1148 | |
1149 | !llvm.dbg.cu = !{!0} |
1150 | !llvm.module.flags = !{!5} |
1151 | |
1152 | !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) |
1153 | !1 = !DIFile(filename: "t.ll", directory: "/") |
1154 | !2 = !{} |
1155 | !5 = !{i32 2, !"Debug Info Version", i32 3} |
1156 | !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) |
1157 | !7 = !DISubroutineType(types: !2) |
1158 | !8 = !{!9} |
1159 | !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) |
1160 | !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned) |
1161 | !11 = !DILocation(line: 1, column: 1, scope: !6) |
1162 | )" ); |
1163 | |
1164 | BasicBlock &Entry = M->getFunction(Name: "f" )->getEntryBlock(); |
1165 | BasicBlock &Exit = *Entry.getNextNode(); |
1166 | M->convertToNewDbgValues(); |
1167 | |
1168 | // Begin by forcing entry block to have dangling DbgVariableRecord. |
1169 | Entry.getTerminator()->eraseFromParent(); |
1170 | ASSERT_NE(Entry.getTrailingDbgRecords(), nullptr); |
1171 | EXPECT_TRUE(Entry.empty()); |
1172 | |
1173 | // Now transfer the entire contents of the exit block into the entry. |
1174 | Entry.splice(ToIt: Entry.end(), FromBB: &Exit, FromBeginIt: Exit.begin(), FromEndIt: Exit.end()); |
1175 | |
1176 | // The trailing DbgVariableRecord should have been placed at the front of |
1177 | // what's been spliced in. |
1178 | Instruction *BInst = &*Entry.begin(); |
1179 | ASSERT_TRUE(BInst->DebugMarker); |
1180 | EXPECT_EQ(BInst->DebugMarker->StoredDbgRecords.size(), 1u); |
1181 | |
1182 | UseNewDbgInfoFormat = false; |
1183 | } |
1184 | |
1185 | // When we remove instructions from the program, adjacent DbgVariableRecords |
1186 | // coalesce together into one DbgMarker. In "old" dbg.value mode you could |
1187 | // re-insert the removed instruction back into the middle of a sequence of |
1188 | // dbg.values. Test that this can be replicated correctly by DbgVariableRecords |
1189 | TEST(BasicBlockDbgInfoTest, RemoveInstAndReinsert) { |
1190 | LLVMContext C; |
1191 | UseNewDbgInfoFormat = true; |
1192 | |
1193 | std::unique_ptr<Module> M = parseIR(C, IR: R"( |
1194 | define i16 @f(i16 %a) !dbg !6 { |
1195 | entry: |
1196 | %qux = sub i16 %a, 0 |
1197 | call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11 |
1198 | %foo = add i16 %a, %a |
1199 | call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11 |
1200 | ret i16 1 |
1201 | } |
1202 | declare void @llvm.dbg.value(metadata, metadata, metadata) |
1203 | |
1204 | !llvm.dbg.cu = !{!0} |
1205 | !llvm.module.flags = !{!5} |
1206 | |
1207 | !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) |
1208 | !1 = !DIFile(filename: "t.ll", directory: "/") |
1209 | !2 = !{} |
1210 | !5 = !{i32 2, !"Debug Info Version", i32 3} |
1211 | !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) |
1212 | !7 = !DISubroutineType(types: !2) |
1213 | !8 = !{!9} |
1214 | !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) |
1215 | !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned) |
1216 | !11 = !DILocation(line: 1, column: 1, scope: !6) |
1217 | )" ); |
1218 | |
1219 | BasicBlock &Entry = M->getFunction(Name: "f" )->getEntryBlock(); |
1220 | M->convertToNewDbgValues(); |
1221 | |
1222 | // Fetch the relevant instructions from the converted function. |
1223 | Instruction *SubInst = &*Entry.begin(); |
1224 | ASSERT_TRUE(isa<BinaryOperator>(SubInst)); |
1225 | Instruction *AddInst = SubInst->getNextNode(); |
1226 | ASSERT_TRUE(isa<BinaryOperator>(AddInst)); |
1227 | Instruction *RetInst = AddInst->getNextNode(); |
1228 | ASSERT_TRUE(isa<ReturnInst>(RetInst)); |
1229 | |
1230 | // add and sub should both have one DbgVariableRecord on add and ret. |
1231 | EXPECT_FALSE(SubInst->hasDbgRecords()); |
1232 | EXPECT_TRUE(AddInst->hasDbgRecords()); |
1233 | EXPECT_TRUE(RetInst->hasDbgRecords()); |
1234 | auto R1 = AddInst->getDbgRecordRange(); |
1235 | EXPECT_EQ(std::distance(R1.begin(), R1.end()), 1u); |
1236 | auto R2 = RetInst->getDbgRecordRange(); |
1237 | EXPECT_EQ(std::distance(R2.begin(), R2.end()), 1u); |
1238 | |
1239 | // The Supported (TM) code sequence for removing then reinserting insts |
1240 | // after another instruction: |
1241 | std::optional<DbgVariableRecord::self_iterator> Pos = |
1242 | AddInst->getDbgReinsertionPosition(); |
1243 | AddInst->removeFromParent(); |
1244 | |
1245 | // We should have a re-insertion position. |
1246 | ASSERT_TRUE(Pos); |
1247 | // Both DbgVariableRecords should now be attached to the ret inst. |
1248 | auto R3 = RetInst->getDbgRecordRange(); |
1249 | EXPECT_EQ(std::distance(R3.begin(), R3.end()), 2u); |
1250 | |
1251 | // Re-insert and re-insert. |
1252 | AddInst->insertAfter(InsertPos: SubInst); |
1253 | Entry.reinsertInstInDbgRecords(I: AddInst, Pos); |
1254 | // We should be back into a position of having one DbgVariableRecord on add |
1255 | // and ret. |
1256 | EXPECT_FALSE(SubInst->hasDbgRecords()); |
1257 | EXPECT_TRUE(AddInst->hasDbgRecords()); |
1258 | EXPECT_TRUE(RetInst->hasDbgRecords()); |
1259 | auto R4 = AddInst->getDbgRecordRange(); |
1260 | EXPECT_EQ(std::distance(R4.begin(), R4.end()), 1u); |
1261 | auto R5 = RetInst->getDbgRecordRange(); |
1262 | EXPECT_EQ(std::distance(R5.begin(), R5.end()), 1u); |
1263 | |
1264 | UseNewDbgInfoFormat = false; |
1265 | } |
1266 | |
1267 | // Test instruction removal and re-insertion, this time with one |
1268 | // DbgVariableRecord that should hop up one instruction. |
1269 | TEST(BasicBlockDbgInfoTest, RemoveInstAndReinsertForOneDbgVariableRecord) { |
1270 | LLVMContext C; |
1271 | UseNewDbgInfoFormat = true; |
1272 | |
1273 | std::unique_ptr<Module> M = parseIR(C, IR: R"( |
1274 | define i16 @f(i16 %a) !dbg !6 { |
1275 | entry: |
1276 | %qux = sub i16 %a, 0 |
1277 | call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11 |
1278 | %foo = add i16 %a, %a |
1279 | ret i16 1 |
1280 | } |
1281 | declare void @llvm.dbg.value(metadata, metadata, metadata) |
1282 | |
1283 | !llvm.dbg.cu = !{!0} |
1284 | !llvm.module.flags = !{!5} |
1285 | |
1286 | !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) |
1287 | !1 = !DIFile(filename: "t.ll", directory: "/") |
1288 | !2 = !{} |
1289 | !5 = !{i32 2, !"Debug Info Version", i32 3} |
1290 | !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) |
1291 | !7 = !DISubroutineType(types: !2) |
1292 | !8 = !{!9} |
1293 | !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) |
1294 | !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned) |
1295 | !11 = !DILocation(line: 1, column: 1, scope: !6) |
1296 | )" ); |
1297 | |
1298 | BasicBlock &Entry = M->getFunction(Name: "f" )->getEntryBlock(); |
1299 | M->convertToNewDbgValues(); |
1300 | |
1301 | // Fetch the relevant instructions from the converted function. |
1302 | Instruction *SubInst = &*Entry.begin(); |
1303 | ASSERT_TRUE(isa<BinaryOperator>(SubInst)); |
1304 | Instruction *AddInst = SubInst->getNextNode(); |
1305 | ASSERT_TRUE(isa<BinaryOperator>(AddInst)); |
1306 | Instruction *RetInst = AddInst->getNextNode(); |
1307 | ASSERT_TRUE(isa<ReturnInst>(RetInst)); |
1308 | |
1309 | // There should be one DbgVariableRecord. |
1310 | EXPECT_FALSE(SubInst->hasDbgRecords()); |
1311 | EXPECT_TRUE(AddInst->hasDbgRecords()); |
1312 | EXPECT_FALSE(RetInst->hasDbgRecords()); |
1313 | auto R1 = AddInst->getDbgRecordRange(); |
1314 | EXPECT_EQ(std::distance(R1.begin(), R1.end()), 1u); |
1315 | |
1316 | // The Supported (TM) code sequence for removing then reinserting insts: |
1317 | std::optional<DbgVariableRecord::self_iterator> Pos = |
1318 | AddInst->getDbgReinsertionPosition(); |
1319 | AddInst->removeFromParent(); |
1320 | |
1321 | // No re-insertion position as there were no DbgVariableRecords on the ret. |
1322 | ASSERT_FALSE(Pos); |
1323 | // The single DbgVariableRecord should now be attached to the ret inst. |
1324 | EXPECT_TRUE(RetInst->hasDbgRecords()); |
1325 | auto R2 = RetInst->getDbgRecordRange(); |
1326 | EXPECT_EQ(std::distance(R2.begin(), R2.end()), 1u); |
1327 | |
1328 | // Re-insert and re-insert. |
1329 | AddInst->insertAfter(InsertPos: SubInst); |
1330 | Entry.reinsertInstInDbgRecords(I: AddInst, Pos); |
1331 | // We should be back into a position of having one DbgVariableRecord on the |
1332 | // AddInst. |
1333 | EXPECT_FALSE(SubInst->hasDbgRecords()); |
1334 | EXPECT_TRUE(AddInst->hasDbgRecords()); |
1335 | EXPECT_FALSE(RetInst->hasDbgRecords()); |
1336 | auto R3 = AddInst->getDbgRecordRange(); |
1337 | EXPECT_EQ(std::distance(R3.begin(), R3.end()), 1u); |
1338 | |
1339 | UseNewDbgInfoFormat = false; |
1340 | } |
1341 | |
1342 | // Similar to the above, what if we splice into an empty block with debug-info, |
1343 | // with debug-info at the start of the moving range, that we intend to be |
1344 | // transferred. The dbg.value of %a should remain at the start, but come ahead |
1345 | // of the i16 0 dbg.value. |
1346 | TEST(BasicBlockDbgInfoTest, DbgSpliceToEmpty1) { |
1347 | LLVMContext C; |
1348 | UseNewDbgInfoFormat = true; |
1349 | |
1350 | std::unique_ptr<Module> M = parseIR(C, IR: R"( |
1351 | define i16 @f(i16 %a) !dbg !6 { |
1352 | entry: |
1353 | call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11 |
1354 | br label %exit |
1355 | |
1356 | exit: |
1357 | call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11 |
1358 | %b = add i16 %a, 1, !dbg !11 |
1359 | call void @llvm.dbg.value(metadata i16 1, metadata !9, metadata !DIExpression()), !dbg !11 |
1360 | ret i16 0, !dbg !11 |
1361 | } |
1362 | declare void @llvm.dbg.value(metadata, metadata, metadata) #0 |
1363 | attributes #0 = { nounwind readnone speculatable willreturn } |
1364 | |
1365 | !llvm.dbg.cu = !{!0} |
1366 | !llvm.module.flags = !{!5} |
1367 | |
1368 | !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) |
1369 | !1 = !DIFile(filename: "t.ll", directory: "/") |
1370 | !2 = !{} |
1371 | !5 = !{i32 2, !"Debug Info Version", i32 3} |
1372 | !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) |
1373 | !7 = !DISubroutineType(types: !2) |
1374 | !8 = !{!9} |
1375 | !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) |
1376 | !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned) |
1377 | !11 = !DILocation(line: 1, column: 1, scope: !6) |
1378 | )" ); |
1379 | |
1380 | Function &F = *M->getFunction(Name: "f" ); |
1381 | BasicBlock &Entry = F.getEntryBlock(); |
1382 | BasicBlock &Exit = *Entry.getNextNode(); |
1383 | M->convertToNewDbgValues(); |
1384 | |
1385 | // Begin by forcing entry block to have dangling DbgVariableRecord. |
1386 | Entry.getTerminator()->eraseFromParent(); |
1387 | ASSERT_NE(Entry.getTrailingDbgRecords(), nullptr); |
1388 | EXPECT_TRUE(Entry.empty()); |
1389 | |
1390 | // Now transfer the entire contents of the exit block into the entry. This |
1391 | // includes both dbg.values. |
1392 | Entry.splice(ToIt: Entry.end(), FromBB: &Exit, FromBeginIt: Exit.begin(), FromEndIt: Exit.end()); |
1393 | |
1394 | // We should now have two dbg.values on the first instruction, and they |
1395 | // should be in the correct order of %a, then 0. |
1396 | Instruction *BInst = &*Entry.begin(); |
1397 | ASSERT_TRUE(BInst->hasDbgRecords()); |
1398 | EXPECT_EQ(BInst->DebugMarker->StoredDbgRecords.size(), 2u); |
1399 | SmallVector<DbgVariableRecord *, 2> DbgVariableRecords; |
1400 | for (DbgRecord &DVR : BInst->getDbgRecordRange()) |
1401 | DbgVariableRecords.push_back(Elt: cast<DbgVariableRecord>(Val: &DVR)); |
1402 | |
1403 | EXPECT_EQ(DbgVariableRecords[0]->getVariableLocationOp(0), F.getArg(0)); |
1404 | Value *SecondDVRValue = DbgVariableRecords[1]->getVariableLocationOp(OpIdx: 0); |
1405 | ASSERT_TRUE(isa<ConstantInt>(SecondDVRValue)); |
1406 | EXPECT_EQ(cast<ConstantInt>(SecondDVRValue)->getZExtValue(), 0ull); |
1407 | |
1408 | // No trailing DbgVariableRecords in the entry block now. |
1409 | EXPECT_EQ(Entry.getTrailingDbgRecords(), nullptr); |
1410 | |
1411 | UseNewDbgInfoFormat = false; |
1412 | } |
1413 | |
1414 | // Similar test again, but this time: splice the contents of exit into entry, |
1415 | // with the intention of leaving the first dbg.value (i16 0) behind. |
1416 | TEST(BasicBlockDbgInfoTest, DbgSpliceToEmpty2) { |
1417 | LLVMContext C; |
1418 | UseNewDbgInfoFormat = true; |
1419 | |
1420 | std::unique_ptr<Module> M = parseIR(C, IR: R"( |
1421 | define i16 @f(i16 %a) !dbg !6 { |
1422 | entry: |
1423 | call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11 |
1424 | br label %exit |
1425 | |
1426 | exit: |
1427 | call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11 |
1428 | %b = add i16 %a, 1, !dbg !11 |
1429 | call void @llvm.dbg.value(metadata i16 1, metadata !9, metadata !DIExpression()), !dbg !11 |
1430 | ret i16 0, !dbg !11 |
1431 | } |
1432 | declare void @llvm.dbg.value(metadata, metadata, metadata) #0 |
1433 | attributes #0 = { nounwind readnone speculatable willreturn } |
1434 | |
1435 | !llvm.dbg.cu = !{!0} |
1436 | !llvm.module.flags = !{!5} |
1437 | |
1438 | !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) |
1439 | !1 = !DIFile(filename: "t.ll", directory: "/") |
1440 | !2 = !{} |
1441 | !5 = !{i32 2, !"Debug Info Version", i32 3} |
1442 | !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) |
1443 | !7 = !DISubroutineType(types: !2) |
1444 | !8 = !{!9} |
1445 | !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) |
1446 | !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned) |
1447 | !11 = !DILocation(line: 1, column: 1, scope: !6) |
1448 | )" ); |
1449 | |
1450 | Function &F = *M->getFunction(Name: "f" ); |
1451 | BasicBlock &Entry = F.getEntryBlock(); |
1452 | BasicBlock &Exit = *Entry.getNextNode(); |
1453 | M->convertToNewDbgValues(); |
1454 | |
1455 | // Begin by forcing entry block to have dangling DbgVariableRecord. |
1456 | Entry.getTerminator()->eraseFromParent(); |
1457 | ASSERT_NE(Entry.getTrailingDbgRecords(), nullptr); |
1458 | EXPECT_TRUE(Entry.empty()); |
1459 | |
1460 | // Now transfer into the entry block -- fetching the first instruction with |
1461 | // begin and then calling getIterator clears the "head" bit, meaning that the |
1462 | // range to move will not include any leading DbgVariableRecords. |
1463 | Entry.splice(ToIt: Entry.end(), FromBB: &Exit, FromBeginIt: Exit.begin()->getIterator(), FromEndIt: Exit.end()); |
1464 | |
1465 | // We should now have one dbg.values on the first instruction, %a. |
1466 | Instruction *BInst = &*Entry.begin(); |
1467 | ASSERT_TRUE(BInst->hasDbgRecords()); |
1468 | EXPECT_EQ(BInst->DebugMarker->StoredDbgRecords.size(), 1u); |
1469 | SmallVector<DbgVariableRecord *, 2> DbgVariableRecords; |
1470 | for (DbgRecord &DVR : BInst->getDbgRecordRange()) |
1471 | DbgVariableRecords.push_back(Elt: cast<DbgVariableRecord>(Val: &DVR)); |
1472 | |
1473 | EXPECT_EQ(DbgVariableRecords[0]->getVariableLocationOp(0), F.getArg(0)); |
1474 | // No trailing DbgVariableRecords in the entry block now. |
1475 | EXPECT_EQ(Entry.getTrailingDbgRecords(), nullptr); |
1476 | |
1477 | // We should have nothing left in the exit block... |
1478 | EXPECT_TRUE(Exit.empty()); |
1479 | // ... except for some dangling DbgVariableRecords. |
1480 | EXPECT_NE(Exit.getTrailingDbgRecords(), nullptr); |
1481 | EXPECT_FALSE(Exit.getTrailingDbgRecords()->empty()); |
1482 | Exit.getTrailingDbgRecords()->eraseFromParent(); |
1483 | Exit.deleteTrailingDbgRecords(); |
1484 | |
1485 | UseNewDbgInfoFormat = false; |
1486 | } |
1487 | |
1488 | // What if we moveBefore end() -- there might be no debug-info there, in which |
1489 | // case we shouldn't crash. |
1490 | TEST(BasicBlockDbgInfoTest, DbgMoveToEnd) { |
1491 | LLVMContext C; |
1492 | UseNewDbgInfoFormat = true; |
1493 | |
1494 | std::unique_ptr<Module> M = parseIR(C, IR: R"( |
1495 | define i16 @f(i16 %a) !dbg !6 { |
1496 | entry: |
1497 | br label %exit |
1498 | |
1499 | exit: |
1500 | ret i16 0, !dbg !11 |
1501 | } |
1502 | declare void @llvm.dbg.value(metadata, metadata, metadata) #0 |
1503 | attributes #0 = { nounwind readnone speculatable willreturn } |
1504 | |
1505 | !llvm.dbg.cu = !{!0} |
1506 | !llvm.module.flags = !{!5} |
1507 | |
1508 | !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) |
1509 | !1 = !DIFile(filename: "t.ll", directory: "/") |
1510 | !2 = !{} |
1511 | !5 = !{i32 2, !"Debug Info Version", i32 3} |
1512 | !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) |
1513 | !7 = !DISubroutineType(types: !2) |
1514 | !8 = !{!9} |
1515 | !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) |
1516 | !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned) |
1517 | !11 = !DILocation(line: 1, column: 1, scope: !6) |
1518 | )" ); |
1519 | |
1520 | Function &F = *M->getFunction(Name: "f" ); |
1521 | BasicBlock &Entry = F.getEntryBlock(); |
1522 | BasicBlock &Exit = *Entry.getNextNode(); |
1523 | M->convertToNewDbgValues(); |
1524 | |
1525 | // Move the return to the end of the entry block. |
1526 | Instruction *Br = Entry.getTerminator(); |
1527 | Instruction *Ret = Exit.getTerminator(); |
1528 | EXPECT_EQ(Entry.getTrailingDbgRecords(), nullptr); |
1529 | Ret->moveBefore(BB&: Entry, I: Entry.end()); |
1530 | Br->eraseFromParent(); |
1531 | |
1532 | // There should continue to not be any debug-info anywhere. |
1533 | EXPECT_EQ(Entry.getTrailingDbgRecords(), nullptr); |
1534 | EXPECT_EQ(Exit.getTrailingDbgRecords(), nullptr); |
1535 | EXPECT_FALSE(Ret->hasDbgRecords()); |
1536 | |
1537 | UseNewDbgInfoFormat = false; |
1538 | } |
1539 | |
1540 | } // End anonymous namespace. |
1541 | |