xref: /llvm-project/llvm/unittests/IR/BasicBlockDbgInfoTest.cpp (revision 8e702735090388a3231a863e343f880d0f96fecb)
1b002b38fSJeremy Morse //===- llvm/unittest/IR/BasicBlockTest.cpp - BasicBlock unit tests --------===//
2b002b38fSJeremy Morse //
3b002b38fSJeremy Morse // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b002b38fSJeremy Morse // See https://llvm.org/LICENSE.txt for license information.
5b002b38fSJeremy Morse // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b002b38fSJeremy Morse //
7b002b38fSJeremy Morse //===----------------------------------------------------------------------===//
8b002b38fSJeremy Morse 
9b002b38fSJeremy Morse #include "llvm/IR/BasicBlock.h"
10b002b38fSJeremy Morse #include "llvm/IR/DebugInfo.h"
11b002b38fSJeremy Morse #include "llvm/ADT/STLExtras.h"
12b002b38fSJeremy Morse #include "llvm/AsmParser/Parser.h"
13b002b38fSJeremy Morse #include "llvm/IR/Function.h"
14b002b38fSJeremy Morse #include "llvm/IR/IRBuilder.h"
15b002b38fSJeremy Morse #include "llvm/IR/Instruction.h"
16b002b38fSJeremy Morse #include "llvm/IR/Instructions.h"
17b002b38fSJeremy Morse #include "llvm/IR/LLVMContext.h"
18b002b38fSJeremy Morse #include "llvm/IR/Module.h"
19b002b38fSJeremy Morse #include "llvm/IR/NoFolder.h"
20b002b38fSJeremy Morse #include "llvm/IR/Verifier.h"
21b002b38fSJeremy Morse #include "llvm/Support/SourceMgr.h"
22b002b38fSJeremy Morse #include "gmock/gmock-matchers.h"
23b002b38fSJeremy Morse #include "gtest/gtest.h"
24b002b38fSJeremy Morse #include <memory>
25b002b38fSJeremy Morse 
26b002b38fSJeremy Morse using namespace llvm;
27b002b38fSJeremy Morse 
28b002b38fSJeremy Morse static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
29b002b38fSJeremy Morse   SMDiagnostic Err;
30b002b38fSJeremy Morse   std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
31b002b38fSJeremy Morse   if (!Mod)
32b002b38fSJeremy Morse     Err.print("BasicBlockDbgInfoTest", errs());
33b002b38fSJeremy Morse   return Mod;
34b002b38fSJeremy Morse }
35b002b38fSJeremy Morse 
36b002b38fSJeremy Morse namespace {
37b002b38fSJeremy Morse 
3818669592SJeremy Morse // We can occasionally moveAfter an instruction so that it moves to the
3918669592SJeremy Morse // position that it already resides at. This is fine -- but gets complicated
4018669592SJeremy Morse // with dbg.value intrinsics. By moving an instruction, we can end up changing
4118669592SJeremy Morse // nothing but the location of debug-info intrinsics. That has to be modelled
42ffd08c77SStephen Tozer // by DbgVariableRecords, the dbg.value replacement.
4318669592SJeremy Morse TEST(BasicBlockDbgInfoTest, InsertAfterSelf) {
4418669592SJeremy Morse   LLVMContext C;
4518669592SJeremy Morse   std::unique_ptr<Module> M = parseIR(C, R"(
4618669592SJeremy Morse     define i16 @f(i16 %a) !dbg !6 {
4718669592SJeremy Morse       call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
4818669592SJeremy Morse       %b = add i16 %a, 1, !dbg !11
4918669592SJeremy Morse       call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
5018669592SJeremy Morse       %c = add i16 %b, 1, !dbg !11
5118669592SJeremy Morse       ret i16 0, !dbg !11
5218669592SJeremy Morse     }
5318669592SJeremy Morse     declare void @llvm.dbg.value(metadata, metadata, metadata) #0
5418669592SJeremy Morse     attributes #0 = { nounwind readnone speculatable willreturn }
5518669592SJeremy Morse 
5618669592SJeremy Morse     !llvm.dbg.cu = !{!0}
5718669592SJeremy Morse     !llvm.module.flags = !{!5}
5818669592SJeremy Morse 
5918669592SJeremy Morse     !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
6018669592SJeremy Morse     !1 = !DIFile(filename: "t.ll", directory: "/")
6118669592SJeremy Morse     !2 = !{}
6218669592SJeremy Morse     !5 = !{i32 2, !"Debug Info Version", i32 3}
6318669592SJeremy Morse     !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
6418669592SJeremy Morse     !7 = !DISubroutineType(types: !2)
6518669592SJeremy Morse     !8 = !{!9}
6618669592SJeremy Morse     !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
6718669592SJeremy Morse     !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
6818669592SJeremy Morse     !11 = !DILocation(line: 1, column: 1, scope: !6)
6918669592SJeremy Morse )");
7018669592SJeremy Morse 
7118669592SJeremy Morse   // Fetch the entry block.
7218669592SJeremy Morse   BasicBlock &BB = M->getFunction("f")->getEntryBlock();
7318669592SJeremy Morse 
7418669592SJeremy Morse   Instruction *Inst1 = &*BB.begin();
7518669592SJeremy Morse   Instruction *Inst2 = &*std::next(BB.begin());
7618669592SJeremy Morse   Instruction *RetInst = &*std::next(Inst2->getIterator());
7715f3f446SStephen Tozer   EXPECT_TRUE(Inst1->hasDbgRecords());
7815f3f446SStephen Tozer   EXPECT_TRUE(Inst2->hasDbgRecords());
7915f3f446SStephen Tozer   EXPECT_FALSE(RetInst->hasDbgRecords());
8018669592SJeremy Morse 
8118669592SJeremy Morse   // If we move Inst2 to be after Inst1, then it comes _immediately_ after. Were
8218669592SJeremy Morse   // we in dbg.value form we would then have:
8318669592SJeremy Morse   //    dbg.value
8418669592SJeremy Morse   //    %b = add
8518669592SJeremy Morse   //    %c = add
8618669592SJeremy Morse   //    dbg.value
87ffd08c77SStephen Tozer   // Check that this is replicated by DbgVariableRecords.
8818669592SJeremy Morse   Inst2->moveAfter(Inst1);
8918669592SJeremy Morse 
90ffd08c77SStephen Tozer   // Inst1 should only have one DbgVariableRecord on it.
9115f3f446SStephen Tozer   EXPECT_TRUE(Inst1->hasDbgRecords());
9215f3f446SStephen Tozer   auto Range1 = Inst1->getDbgRecordRange();
9318669592SJeremy Morse   EXPECT_EQ(std::distance(Range1.begin(), Range1.end()), 1u);
9418669592SJeremy Morse   // Inst2 should have none.
9515f3f446SStephen Tozer   EXPECT_FALSE(Inst2->hasDbgRecords());
9618669592SJeremy Morse   // While the return inst should now have one on it.
9715f3f446SStephen Tozer   EXPECT_TRUE(RetInst->hasDbgRecords());
9815f3f446SStephen Tozer   auto Range2 = RetInst->getDbgRecordRange();
9918669592SJeremy Morse   EXPECT_EQ(std::distance(Range2.begin(), Range2.end()), 1u);
10018669592SJeremy Morse }
10118669592SJeremy Morse 
1020fb50371SFranklin Zhang TEST(BasicBlockDbgInfoTest, SplitBasicBlockBefore) {
1030fb50371SFranklin Zhang   LLVMContext C;
1040fb50371SFranklin Zhang   std::unique_ptr<Module> M = parseIR(C, R"---(
1050fb50371SFranklin Zhang     define dso_local void @func() #0 !dbg !10 {
1060fb50371SFranklin Zhang       %1 = alloca i32, align 4
1070fb50371SFranklin Zhang       tail call void @llvm.dbg.declare(metadata ptr %1, metadata !14, metadata !DIExpression()), !dbg !16
1080fb50371SFranklin Zhang       store i32 2, ptr %1, align 4, !dbg !16
1090fb50371SFranklin Zhang       ret void, !dbg !17
1100fb50371SFranklin Zhang     }
1110fb50371SFranklin Zhang 
1120fb50371SFranklin Zhang     declare void @llvm.dbg.declare(metadata, metadata, metadata) #0
1130fb50371SFranklin Zhang 
1140fb50371SFranklin Zhang     attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
1150fb50371SFranklin Zhang 
1160fb50371SFranklin Zhang     !llvm.dbg.cu = !{!0}
1170fb50371SFranklin Zhang     !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
1180fb50371SFranklin Zhang     !llvm.ident = !{!9}
1190fb50371SFranklin Zhang 
1200fb50371SFranklin Zhang     !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "dummy", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
1210fb50371SFranklin Zhang     !1 = !DIFile(filename: "dummy", directory: "dummy")
1220fb50371SFranklin Zhang     !2 = !{i32 7, !"Dwarf Version", i32 5}
1230fb50371SFranklin Zhang     !3 = !{i32 2, !"Debug Info Version", i32 3}
1240fb50371SFranklin Zhang     !4 = !{i32 1, !"wchar_size", i32 4}
1250fb50371SFranklin Zhang     !5 = !{i32 8, !"PIC Level", i32 2}
1260fb50371SFranklin Zhang     !6 = !{i32 7, !"PIE Level", i32 2}
1270fb50371SFranklin Zhang     !7 = !{i32 7, !"uwtable", i32 2}
1280fb50371SFranklin Zhang     !8 = !{i32 7, !"frame-pointer", i32 2}
1290fb50371SFranklin Zhang     !9 = !{!"dummy"}
1300fb50371SFranklin Zhang     !10 = distinct !DISubprogram(name: "func", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !13)
1310fb50371SFranklin Zhang     !11 = !DISubroutineType(types: !12)
1320fb50371SFranklin Zhang     !12 = !{null}
1330fb50371SFranklin Zhang     !13 = !{}
1340fb50371SFranklin Zhang     !14 = !DILocalVariable(name: "a", scope: !10, file: !1, line: 2, type: !15)
1350fb50371SFranklin Zhang     !15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
1360fb50371SFranklin Zhang     !16 = !DILocation(line: 2, column: 6, scope: !10)
1370fb50371SFranklin Zhang     !17 = !DILocation(line: 3, column: 2, scope: !10)
1380fb50371SFranklin Zhang   )---");
1390fb50371SFranklin Zhang   ASSERT_TRUE(M);
1400fb50371SFranklin Zhang 
1410fb50371SFranklin Zhang   Function *F = M->getFunction("func");
1420fb50371SFranklin Zhang 
1430fb50371SFranklin Zhang   BasicBlock &BB = F->getEntryBlock();
144f5815534SOrlando Cazalet-Hyams   auto I = std::prev(BB.end(), 2); // store i32 2, ptr %1.
1450fb50371SFranklin Zhang   BB.splitBasicBlockBefore(I, "before");
1460fb50371SFranklin Zhang 
1470fb50371SFranklin Zhang   BasicBlock &BBBefore = F->getEntryBlock();
148f5815534SOrlando Cazalet-Hyams   auto I2 = std::prev(BBBefore.end()); // br label %1 (new).
1490fb50371SFranklin Zhang   ASSERT_TRUE(I2->hasDbgRecords());
1500fb50371SFranklin Zhang }
1510fb50371SFranklin Zhang 
152b002b38fSJeremy Morse TEST(BasicBlockDbgInfoTest, MarkerOperations) {
153b002b38fSJeremy Morse   LLVMContext C;
154b002b38fSJeremy Morse   std::unique_ptr<Module> M = parseIR(C, R"(
155b002b38fSJeremy Morse     define i16 @f(i16 %a) !dbg !6 {
156b002b38fSJeremy Morse       call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
157b002b38fSJeremy Morse       %b = add i16 %a, 1, !dbg !11
158b002b38fSJeremy Morse       call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
159b002b38fSJeremy Morse       ret i16 0, !dbg !11
160b002b38fSJeremy Morse     }
161b002b38fSJeremy Morse     declare void @llvm.dbg.value(metadata, metadata, metadata) #0
162b002b38fSJeremy Morse     attributes #0 = { nounwind readnone speculatable willreturn }
163b002b38fSJeremy Morse 
164b002b38fSJeremy Morse     !llvm.dbg.cu = !{!0}
165b002b38fSJeremy Morse     !llvm.module.flags = !{!5}
166b002b38fSJeremy Morse 
167b002b38fSJeremy Morse     !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
168b002b38fSJeremy Morse     !1 = !DIFile(filename: "t.ll", directory: "/")
169b002b38fSJeremy Morse     !2 = !{}
170b002b38fSJeremy Morse     !5 = !{i32 2, !"Debug Info Version", i32 3}
171b002b38fSJeremy Morse     !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
172b002b38fSJeremy Morse     !7 = !DISubroutineType(types: !2)
173b002b38fSJeremy Morse     !8 = !{!9}
174b002b38fSJeremy Morse     !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
175b002b38fSJeremy Morse     !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
176b002b38fSJeremy Morse     !11 = !DILocation(line: 1, column: 1, scope: !6)
177b002b38fSJeremy Morse )");
178b002b38fSJeremy Morse 
179b002b38fSJeremy Morse   // Fetch the entry block,
180b002b38fSJeremy Morse   BasicBlock &BB = M->getFunction("f")->getEntryBlock();
181b002b38fSJeremy Morse   EXPECT_EQ(BB.size(), 2u);
182b002b38fSJeremy Morse 
183b002b38fSJeremy Morse   // Fetch out our two markers,
184b002b38fSJeremy Morse   Instruction *Instr1 = &*BB.begin();
185b002b38fSJeremy Morse   Instruction *Instr2 = Instr1->getNextNode();
18675dfa58eSStephen Tozer   DbgMarker *Marker1 = Instr1->DebugMarker;
18775dfa58eSStephen Tozer   DbgMarker *Marker2 = Instr2->DebugMarker;
188360da838SStephen Tozer   // There's no TrailingDbgRecords marker allocated yet.
18975dfa58eSStephen Tozer   DbgMarker *EndMarker = nullptr;
190b002b38fSJeremy Morse 
191b002b38fSJeremy Morse   // Check that the "getMarker" utilities operate as expected.
192b002b38fSJeremy Morse   EXPECT_EQ(BB.getMarker(Instr1->getIterator()), Marker1);
193b002b38fSJeremy Morse   EXPECT_EQ(BB.getMarker(Instr2->getIterator()), Marker2);
194b002b38fSJeremy Morse   EXPECT_EQ(BB.getNextMarker(Instr1), Marker2);
195b002b38fSJeremy Morse   EXPECT_EQ(BB.getNextMarker(Instr2), EndMarker); // Is nullptr.
196b002b38fSJeremy Morse 
197ffd08c77SStephen Tozer   // There should be two DbgVariableRecords,
198360da838SStephen Tozer   EXPECT_EQ(Marker1->StoredDbgRecords.size(), 1u);
199360da838SStephen Tozer   EXPECT_EQ(Marker2->StoredDbgRecords.size(), 1u);
200b002b38fSJeremy Morse 
201b002b38fSJeremy Morse   // Unlink them and try to re-insert them through the basic block.
202ffd08c77SStephen Tozer   DbgRecord *DVR1 = &*Marker1->StoredDbgRecords.begin();
203ffd08c77SStephen Tozer   DbgRecord *DVR2 = &*Marker2->StoredDbgRecords.begin();
204ffd08c77SStephen Tozer   DVR1->removeFromParent();
205ffd08c77SStephen Tozer   DVR2->removeFromParent();
206360da838SStephen Tozer   EXPECT_TRUE(Marker1->StoredDbgRecords.empty());
207360da838SStephen Tozer   EXPECT_TRUE(Marker2->StoredDbgRecords.empty());
208b002b38fSJeremy Morse 
209b002b38fSJeremy Morse   // This should appear in Marker1.
210ffd08c77SStephen Tozer   BB.insertDbgRecordBefore(DVR1, BB.begin());
211360da838SStephen Tozer   EXPECT_EQ(Marker1->StoredDbgRecords.size(), 1u);
212ffd08c77SStephen Tozer   EXPECT_EQ(DVR1, &*Marker1->StoredDbgRecords.begin());
213b002b38fSJeremy Morse 
214b002b38fSJeremy Morse   // This should attach to Marker2.
215ffd08c77SStephen Tozer   BB.insertDbgRecordAfter(DVR2, &*BB.begin());
216360da838SStephen Tozer   EXPECT_EQ(Marker2->StoredDbgRecords.size(), 1u);
217ffd08c77SStephen Tozer   EXPECT_EQ(DVR2, &*Marker2->StoredDbgRecords.begin());
218b002b38fSJeremy Morse 
219ffd08c77SStephen Tozer   // Now, how about removing instructions? That should cause any
220ffd08c77SStephen Tozer   // DbgVariableRecords to "fall down".
221b002b38fSJeremy Morse   Instr1->removeFromParent();
222b002b38fSJeremy Morse   Marker1 = nullptr;
223ffd08c77SStephen Tozer   // DbgVariableRecords should now be in Marker2.
224b002b38fSJeremy Morse   EXPECT_EQ(BB.size(), 1u);
225360da838SStephen Tozer   EXPECT_EQ(Marker2->StoredDbgRecords.size(), 2u);
226b002b38fSJeremy Morse   // They should also be in the correct order.
227ffd08c77SStephen Tozer   SmallVector<DbgRecord *, 2> DVRs;
228ffd08c77SStephen Tozer   for (DbgRecord &DVR : Marker2->getDbgRecordRange())
229ffd08c77SStephen Tozer     DVRs.push_back(&DVR);
230ffd08c77SStephen Tozer   EXPECT_EQ(DVRs[0], DVR1);
231ffd08c77SStephen Tozer   EXPECT_EQ(DVRs[1], DVR2);
232b002b38fSJeremy Morse 
233ffd08c77SStephen Tozer   // If we remove the end instruction, the DbgVariableRecords should fall down
234ffd08c77SStephen Tozer   // into the trailing marker.
23515f3f446SStephen Tozer   EXPECT_EQ(BB.getTrailingDbgRecords(), nullptr);
236b002b38fSJeremy Morse   Instr2->removeFromParent();
237b002b38fSJeremy Morse   EXPECT_TRUE(BB.empty());
23815f3f446SStephen Tozer   EndMarker = BB.getTrailingDbgRecords();
239b002b38fSJeremy Morse   ASSERT_NE(EndMarker, nullptr);
240360da838SStephen Tozer   EXPECT_EQ(EndMarker->StoredDbgRecords.size(), 2u);
241b002b38fSJeremy Morse   // Again, these should arrive in the correct order.
242b002b38fSJeremy Morse 
243ffd08c77SStephen Tozer   DVRs.clear();
244ffd08c77SStephen Tozer   for (DbgRecord &DVR : EndMarker->getDbgRecordRange())
245ffd08c77SStephen Tozer     DVRs.push_back(&DVR);
246ffd08c77SStephen Tozer   EXPECT_EQ(DVRs[0], DVR1);
247ffd08c77SStephen Tozer   EXPECT_EQ(DVRs[1], DVR2);
248b002b38fSJeremy Morse 
249b002b38fSJeremy Morse   // Inserting a normal instruction at the beginning: shouldn't dislodge the
250ffd08c77SStephen Tozer   // DbgVariableRecords. It's intended to not go at the start.
251b002b38fSJeremy Morse   Instr1->insertBefore(BB, BB.begin());
252360da838SStephen Tozer   EXPECT_EQ(EndMarker->StoredDbgRecords.size(), 2u);
253b002b38fSJeremy Morse   Instr1->removeFromParent();
254b002b38fSJeremy Morse 
255ffd08c77SStephen Tozer   // Inserting at end(): should dislodge the DbgVariableRecords, if they were
256ffd08c77SStephen Tozer   // dbg.values then they would sit "above" the new instruction.
257b002b38fSJeremy Morse   Instr1->insertBefore(BB, BB.end());
25875dfa58eSStephen Tozer   EXPECT_EQ(Instr1->DebugMarker->StoredDbgRecords.size(), 2u);
259ddc49357SJeremy Morse   // We should de-allocate the trailing marker when something is inserted
260ddc49357SJeremy Morse   // at end().
26115f3f446SStephen Tozer   EXPECT_EQ(BB.getTrailingDbgRecords(), nullptr);
262b002b38fSJeremy Morse 
263ffd08c77SStephen Tozer   // Remove Instr1: now the DbgVariableRecords will fall down again,
264b002b38fSJeremy Morse   Instr1->removeFromParent();
26515f3f446SStephen Tozer   EndMarker = BB.getTrailingDbgRecords();
266360da838SStephen Tozer   EXPECT_EQ(EndMarker->StoredDbgRecords.size(), 2u);
267b002b38fSJeremy Morse 
268b002b38fSJeremy Morse   // Inserting a terminator, however it's intended, should dislodge the
269ffd08c77SStephen Tozer   // trailing DbgVariableRecords, as it's the clear intention of the caller that
270ffd08c77SStephen Tozer   // this be the final instr in the block, and DbgVariableRecords aren't allowed
271ffd08c77SStephen Tozer   // to live off the end forever.
272b002b38fSJeremy Morse   Instr2->insertBefore(BB, BB.begin());
27375dfa58eSStephen Tozer   EXPECT_EQ(Instr2->DebugMarker->StoredDbgRecords.size(), 2u);
27415f3f446SStephen Tozer   EXPECT_EQ(BB.getTrailingDbgRecords(), nullptr);
275b002b38fSJeremy Morse 
276b002b38fSJeremy Morse   // Teardown,
277b002b38fSJeremy Morse   Instr1->insertBefore(BB, BB.begin());
278b002b38fSJeremy Morse }
279b002b38fSJeremy Morse 
280b002b38fSJeremy Morse TEST(BasicBlockDbgInfoTest, HeadBitOperations) {
281b002b38fSJeremy Morse   LLVMContext C;
282b002b38fSJeremy Morse   std::unique_ptr<Module> M = parseIR(C, R"(
283b002b38fSJeremy Morse     define i16 @f(i16 %a) !dbg !6 {
284b002b38fSJeremy Morse       %b = add i16 %a, 1, !dbg !11
285b002b38fSJeremy Morse       call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
286b002b38fSJeremy Morse       %c = add i16 %a, 1, !dbg !11
287b002b38fSJeremy Morse       %d = add i16 %a, 1, !dbg !11
288b002b38fSJeremy Morse       ret i16 0, !dbg !11
289b002b38fSJeremy Morse     }
290b002b38fSJeremy Morse     declare void @llvm.dbg.value(metadata, metadata, metadata) #0
291b002b38fSJeremy Morse     attributes #0 = { nounwind readnone speculatable willreturn }
292b002b38fSJeremy Morse 
293b002b38fSJeremy Morse     !llvm.dbg.cu = !{!0}
294b002b38fSJeremy Morse     !llvm.module.flags = !{!5}
295b002b38fSJeremy Morse 
296b002b38fSJeremy Morse     !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
297b002b38fSJeremy Morse     !1 = !DIFile(filename: "t.ll", directory: "/")
298b002b38fSJeremy Morse     !2 = !{}
299b002b38fSJeremy Morse     !5 = !{i32 2, !"Debug Info Version", i32 3}
300b002b38fSJeremy Morse     !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
301b002b38fSJeremy Morse     !7 = !DISubroutineType(types: !2)
302b002b38fSJeremy Morse     !8 = !{!9}
303b002b38fSJeremy Morse     !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
304b002b38fSJeremy Morse     !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
305b002b38fSJeremy Morse     !11 = !DILocation(line: 1, column: 1, scope: !6)
306b002b38fSJeremy Morse )");
307b002b38fSJeremy Morse 
308b002b38fSJeremy Morse   // Test that the movement of debug-data when using moveBefore etc and
309b002b38fSJeremy Morse   // insertBefore etc are governed by the "head" bit of iterators.
310b002b38fSJeremy Morse   BasicBlock &BB = M->getFunction("f")->getEntryBlock();
311b002b38fSJeremy Morse 
312b002b38fSJeremy Morse   // Test that the head bit behaves as expected: it should be set when the
313b002b38fSJeremy Morse   // code wants the _start_ of the block, but not otherwise.
314b002b38fSJeremy Morse   EXPECT_TRUE(BB.getFirstInsertionPt().getHeadBit());
315b002b38fSJeremy Morse   BasicBlock::iterator BeginIt = BB.begin();
316b002b38fSJeremy Morse   EXPECT_TRUE(BeginIt.getHeadBit());
317b002b38fSJeremy Morse   // If you launder the instruction pointer through dereferencing and then
318b002b38fSJeremy Morse   // get the iterator again with getIterator, the head bit is lost. This is
319b002b38fSJeremy Morse   // deliberate: if you're calling getIterator, then you're requesting an
320b002b38fSJeremy Morse   // iterator for the position of _this_ instruction, not "the start of this
321b002b38fSJeremy Morse   // block".
322b002b38fSJeremy Morse   BasicBlock::iterator BeginIt2 = BeginIt->getIterator();
323b002b38fSJeremy Morse   EXPECT_FALSE(BeginIt2.getHeadBit());
324b002b38fSJeremy Morse 
325b002b38fSJeremy Morse   // Fetch some instruction pointers.
326b002b38fSJeremy Morse   Instruction *BInst = &*BeginIt;
327b002b38fSJeremy Morse   Instruction *CInst = BInst->getNextNode();
328b002b38fSJeremy Morse   Instruction *DInst = CInst->getNextNode();
329b002b38fSJeremy Morse   // CInst should have debug-info.
33075dfa58eSStephen Tozer   ASSERT_TRUE(CInst->DebugMarker);
33175dfa58eSStephen Tozer   EXPECT_FALSE(CInst->DebugMarker->StoredDbgRecords.empty());
332b002b38fSJeremy Morse 
333ffd08c77SStephen Tozer   // If we move "c" to the start of the block, just normally, then the
334ffd08c77SStephen Tozer   // DbgVariableRecords should fall down to "d".
335b002b38fSJeremy Morse   CInst->moveBefore(BB, BeginIt2);
33675dfa58eSStephen Tozer   EXPECT_TRUE(!CInst->DebugMarker ||
33775dfa58eSStephen Tozer               CInst->DebugMarker->StoredDbgRecords.empty());
33875dfa58eSStephen Tozer   ASSERT_TRUE(DInst->DebugMarker);
33975dfa58eSStephen Tozer   EXPECT_FALSE(DInst->DebugMarker->StoredDbgRecords.empty());
340b002b38fSJeremy Morse 
341b002b38fSJeremy Morse   // Wheras if we move D to the start of the block with moveBeforePreserving,
342ffd08c77SStephen Tozer   // the DbgVariableRecords should move with it.
343b002b38fSJeremy Morse   DInst->moveBeforePreserving(BB, BB.begin());
34475dfa58eSStephen Tozer   EXPECT_FALSE(DInst->DebugMarker->StoredDbgRecords.empty());
345b002b38fSJeremy Morse   EXPECT_EQ(&*BB.begin(), DInst);
346b002b38fSJeremy Morse 
347ffd08c77SStephen Tozer   // Similarly, moveAfterPreserving "D" to "C" should move DbgVariableRecords
348ffd08c77SStephen Tozer   // with "D".
349b002b38fSJeremy Morse   DInst->moveAfterPreserving(CInst);
35075dfa58eSStephen Tozer   EXPECT_FALSE(DInst->DebugMarker->StoredDbgRecords.empty());
351b002b38fSJeremy Morse 
352b002b38fSJeremy Morse   // (move back to the start...)
353b002b38fSJeremy Morse   DInst->moveBeforePreserving(BB, BB.begin());
354b002b38fSJeremy Morse 
355ffd08c77SStephen Tozer   // Current order of insts: "D -> C -> B -> Ret". DbgVariableRecords on "D".
356b002b38fSJeremy Morse   // If we move "C" to the beginning of the block, it should go before the
357ffd08c77SStephen Tozer   // DbgVariableRecords. They'll stay on "D".
358b002b38fSJeremy Morse   CInst->moveBefore(BB, BB.begin());
35975dfa58eSStephen Tozer   EXPECT_TRUE(!CInst->DebugMarker ||
36075dfa58eSStephen Tozer               CInst->DebugMarker->StoredDbgRecords.empty());
36175dfa58eSStephen Tozer   EXPECT_FALSE(DInst->DebugMarker->StoredDbgRecords.empty());
362b002b38fSJeremy Morse   EXPECT_EQ(&*BB.begin(), CInst);
363b002b38fSJeremy Morse   EXPECT_EQ(CInst->getNextNode(), DInst);
364b002b38fSJeremy Morse 
365b002b38fSJeremy Morse   // Move back.
366*8e702735SJeremy Morse   CInst->moveBefore(BInst->getIterator());
367b002b38fSJeremy Morse   EXPECT_EQ(&*BB.begin(), DInst);
368b002b38fSJeremy Morse 
369ffd08c77SStephen Tozer   // Current order of insts: "D -> C -> B -> Ret". DbgVariableRecords on "D".
370b002b38fSJeremy Morse   // Now move CInst to the position of DInst, but using getIterator instead of
371b002b38fSJeremy Morse   // BasicBlock::begin. This signals that we want the "C" instruction to be
372ffd08c77SStephen Tozer   // immediately before "D", with any DbgVariableRecords on "D" now moving to
373ffd08c77SStephen Tozer   // "C". It's the equivalent of moving an instruction to the position between a
374b002b38fSJeremy Morse   // run of dbg.values and the next instruction.
375b002b38fSJeremy Morse   CInst->moveBefore(BB, DInst->getIterator());
376ffd08c77SStephen Tozer   // CInst gains the DbgVariableRecords.
37775dfa58eSStephen Tozer   EXPECT_TRUE(!DInst->DebugMarker ||
37875dfa58eSStephen Tozer               DInst->DebugMarker->StoredDbgRecords.empty());
37975dfa58eSStephen Tozer   EXPECT_FALSE(CInst->DebugMarker->StoredDbgRecords.empty());
380b002b38fSJeremy Morse   EXPECT_EQ(&*BB.begin(), CInst);
381b002b38fSJeremy Morse }
382b002b38fSJeremy Morse 
383b002b38fSJeremy Morse TEST(BasicBlockDbgInfoTest, InstrDbgAccess) {
384b002b38fSJeremy Morse   LLVMContext C;
385b002b38fSJeremy Morse   std::unique_ptr<Module> M = parseIR(C, R"(
386b002b38fSJeremy Morse     define i16 @f(i16 %a) !dbg !6 {
387b002b38fSJeremy Morse       %b = add i16 %a, 1, !dbg !11
388b002b38fSJeremy Morse       call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
389b002b38fSJeremy Morse       %c = add i16 %a, 1, !dbg !11
390b002b38fSJeremy Morse       %d = add i16 %a, 1, !dbg !11
391b002b38fSJeremy Morse       ret i16 0, !dbg !11
392b002b38fSJeremy Morse     }
393b002b38fSJeremy Morse     declare void @llvm.dbg.value(metadata, metadata, metadata) #0
394b002b38fSJeremy Morse     attributes #0 = { nounwind readnone speculatable willreturn }
395b002b38fSJeremy Morse 
396b002b38fSJeremy Morse     !llvm.dbg.cu = !{!0}
397b002b38fSJeremy Morse     !llvm.module.flags = !{!5}
398b002b38fSJeremy Morse 
399b002b38fSJeremy Morse     !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
400b002b38fSJeremy Morse     !1 = !DIFile(filename: "t.ll", directory: "/")
401b002b38fSJeremy Morse     !2 = !{}
402b002b38fSJeremy Morse     !5 = !{i32 2, !"Debug Info Version", i32 3}
403b002b38fSJeremy Morse     !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
404b002b38fSJeremy Morse     !7 = !DISubroutineType(types: !2)
405b002b38fSJeremy Morse     !8 = !{!9}
406b002b38fSJeremy Morse     !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
407b002b38fSJeremy Morse     !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
408b002b38fSJeremy Morse     !11 = !DILocation(line: 1, column: 1, scope: !6)
409b002b38fSJeremy Morse )");
410b002b38fSJeremy Morse 
411ffd08c77SStephen Tozer   // Check that DbgVariableRecords can be accessed from Instructions without
41275dfa58eSStephen Tozer   // digging into the depths of DbgMarkers.
413b002b38fSJeremy Morse   BasicBlock &BB = M->getFunction("f")->getEntryBlock();
414b002b38fSJeremy Morse 
415b002b38fSJeremy Morse   Instruction *BInst = &*BB.begin();
416b002b38fSJeremy Morse   Instruction *CInst = BInst->getNextNode();
417b002b38fSJeremy Morse   Instruction *DInst = CInst->getNextNode();
418b002b38fSJeremy Morse 
41975dfa58eSStephen Tozer   ASSERT_FALSE(BInst->DebugMarker);
42075dfa58eSStephen Tozer   ASSERT_TRUE(CInst->DebugMarker);
42175dfa58eSStephen Tozer   ASSERT_EQ(CInst->DebugMarker->StoredDbgRecords.size(), 1u);
42275dfa58eSStephen Tozer   DbgRecord *DVR1 = &*CInst->DebugMarker->StoredDbgRecords.begin();
423ffd08c77SStephen Tozer   ASSERT_TRUE(DVR1);
42415f3f446SStephen Tozer   EXPECT_FALSE(BInst->hasDbgRecords());
425b002b38fSJeremy Morse 
426ffd08c77SStephen Tozer   // Clone DbgVariableRecords from one inst to another. Other arguments to clone
42775dfa58eSStephen Tozer   // are tested in DbgMarker test.
428b002b38fSJeremy Morse   auto Range1 = BInst->cloneDebugInfoFrom(CInst);
42975dfa58eSStephen Tozer   EXPECT_EQ(BInst->DebugMarker->StoredDbgRecords.size(), 1u);
43075dfa58eSStephen Tozer   DbgRecord *DVR2 = &*BInst->DebugMarker->StoredDbgRecords.begin();
431b002b38fSJeremy Morse   EXPECT_EQ(std::distance(Range1.begin(), Range1.end()), 1u);
432ffd08c77SStephen Tozer   EXPECT_EQ(&*Range1.begin(), DVR2);
433ffd08c77SStephen Tozer   EXPECT_NE(DVR1, DVR2);
434b002b38fSJeremy Morse 
435b002b38fSJeremy Morse   // We should be able to get a range over exactly the same information.
43615f3f446SStephen Tozer   auto Range2 = BInst->getDbgRecordRange();
437b002b38fSJeremy Morse   EXPECT_EQ(Range1.begin(), Range2.begin());
438b002b38fSJeremy Morse   EXPECT_EQ(Range1.end(), Range2.end());
439b002b38fSJeremy Morse 
440ffd08c77SStephen Tozer   // We should be able to query if there are DbgVariableRecords,
44115f3f446SStephen Tozer   EXPECT_TRUE(BInst->hasDbgRecords());
44215f3f446SStephen Tozer   EXPECT_TRUE(CInst->hasDbgRecords());
44315f3f446SStephen Tozer   EXPECT_FALSE(DInst->hasDbgRecords());
444b002b38fSJeremy Morse 
445b002b38fSJeremy Morse   // Dropping should be easy,
44615f3f446SStephen Tozer   BInst->dropDbgRecords();
44715f3f446SStephen Tozer   EXPECT_FALSE(BInst->hasDbgRecords());
44875dfa58eSStephen Tozer   EXPECT_EQ(BInst->DebugMarker->StoredDbgRecords.size(), 0u);
449b002b38fSJeremy Morse 
450ffd08c77SStephen Tozer   // And we should be able to drop individual DbgVariableRecords.
451ffd08c77SStephen Tozer   CInst->dropOneDbgRecord(DVR1);
45215f3f446SStephen Tozer   EXPECT_FALSE(CInst->hasDbgRecords());
45375dfa58eSStephen Tozer   EXPECT_EQ(CInst->DebugMarker->StoredDbgRecords.size(), 0u);
454b002b38fSJeremy Morse }
455b002b38fSJeremy Morse 
456b002b38fSJeremy Morse /* Let's recall the big illustration from BasicBlock::spliceDebugInfo:
457b002b38fSJeremy Morse 
458b002b38fSJeremy Morse                                                Dest
459b002b38fSJeremy Morse                                                  |
460b002b38fSJeremy Morse    this-block:    A----A----A                ====A----A----A----A---A---A
461b002b38fSJeremy Morse     Src-block                ++++B---B---B---B:::C
462b002b38fSJeremy Morse                                  |               |
463b002b38fSJeremy Morse                                 First           Last
464b002b38fSJeremy Morse 
465b002b38fSJeremy Morse   in all it's glory. Depending on the bit-configurations for the iterator head
466b002b38fSJeremy Morse   / tail bits on the three named iterators, there are eight ways for a splice to
467b002b38fSJeremy Morse   occur. To save the amount of thinking needed to pack this into one unit test,
468b002b38fSJeremy Morse   just test the same IR eight times with difference splices. The IR shall be
469b002b38fSJeremy Morse   thus:
470b002b38fSJeremy Morse 
471b002b38fSJeremy Morse     define i16 @f(i16 %a) !dbg !6 {
472b002b38fSJeremy Morse     entry:
473b002b38fSJeremy Morse       call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
474b002b38fSJeremy Morse       %b = add i16 %a, 1, !dbg !11
475b002b38fSJeremy Morse       call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
476b002b38fSJeremy Morse       br label %exit, !dbg !11
477b002b38fSJeremy Morse 
478b002b38fSJeremy Morse     exit:
479b002b38fSJeremy Morse       call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
480b002b38fSJeremy Morse       %c = add i16 %b, 1, !dbg !11
481b002b38fSJeremy Morse       ret i16 0, !dbg !11
482b002b38fSJeremy Morse     }
483b002b38fSJeremy Morse 
484b002b38fSJeremy Morse   The iterators will be:
485b002b38fSJeremy Morse     Dest: exit block, "c" instruction.
486b002b38fSJeremy Morse     First: entry block, "b" instruction.
487b002b38fSJeremy Morse     Last: entry block, branch instruction.
488b002b38fSJeremy Morse 
489b002b38fSJeremy Morse   The numbered configurations will be:
490b002b38fSJeremy Morse 
491b002b38fSJeremy Morse        |    Dest-Head   |   First-Head   |   Last-tail
492b002b38fSJeremy Morse    ----+----------------+----------------+------------
493b002b38fSJeremy Morse     0  |      false     |     false      |     false
494b002b38fSJeremy Morse     1  |      true      |     false      |     false
495b002b38fSJeremy Morse     2  |      false     |     true       |     false
496b002b38fSJeremy Morse     3  |      true      |     true       |     false
497b002b38fSJeremy Morse     4  |      false     |     false      |     true
498b002b38fSJeremy Morse     5  |      true      |     false      |     true
499b002b38fSJeremy Morse     6  |      false     |     true       |     true
500b002b38fSJeremy Morse     7  |      true      |     true       |     true
501b002b38fSJeremy Morse 
502b002b38fSJeremy Morse   Each numbered test scenario will also have a short explanation indicating what
503b002b38fSJeremy Morse   this bit configuration represents.
504b002b38fSJeremy Morse */
505b002b38fSJeremy Morse 
506b002b38fSJeremy Morse static const std::string SpliceTestIR = R"(
507b002b38fSJeremy Morse     define i16 @f(i16 %a) !dbg !6 {
508b002b38fSJeremy Morse       call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
509b002b38fSJeremy Morse       %b = add i16 %a, 1, !dbg !11
510b002b38fSJeremy Morse       call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
511b002b38fSJeremy Morse       br label %exit, !dbg !11
512b002b38fSJeremy Morse 
513b002b38fSJeremy Morse     exit:
514b002b38fSJeremy Morse       call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
515b002b38fSJeremy Morse       %c = add i16 %b, 1, !dbg !11
516b002b38fSJeremy Morse       ret i16 0, !dbg !11
517b002b38fSJeremy Morse     }
518b002b38fSJeremy Morse     declare void @llvm.dbg.value(metadata, metadata, metadata) #0
519b002b38fSJeremy Morse     attributes #0 = { nounwind readnone speculatable willreturn }
520b002b38fSJeremy Morse 
521b002b38fSJeremy Morse     !llvm.dbg.cu = !{!0}
522b002b38fSJeremy Morse     !llvm.module.flags = !{!5}
523b002b38fSJeremy Morse 
524b002b38fSJeremy Morse     !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
525b002b38fSJeremy Morse     !1 = !DIFile(filename: "t.ll", directory: "/")
526b002b38fSJeremy Morse     !2 = !{}
527b002b38fSJeremy Morse     !5 = !{i32 2, !"Debug Info Version", i32 3}
528b002b38fSJeremy Morse     !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
529b002b38fSJeremy Morse     !7 = !DISubroutineType(types: !2)
530b002b38fSJeremy Morse     !8 = !{!9}
531b002b38fSJeremy Morse     !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
532b002b38fSJeremy Morse     !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
533b002b38fSJeremy Morse     !11 = !DILocation(line: 1, column: 1, scope: !6)
534b002b38fSJeremy Morse )";
535b002b38fSJeremy Morse 
536b002b38fSJeremy Morse class DbgSpliceTest : public ::testing::Test {
537b002b38fSJeremy Morse protected:
538b002b38fSJeremy Morse   LLVMContext C;
539b002b38fSJeremy Morse   std::unique_ptr<Module> M;
540b002b38fSJeremy Morse   BasicBlock *BBEntry, *BBExit;
541b002b38fSJeremy Morse   BasicBlock::iterator Dest, First, Last;
542b002b38fSJeremy Morse   Instruction *BInst, *Branch, *CInst;
543ffd08c77SStephen Tozer   DbgVariableRecord *DVRA, *DVRB, *DVRConst;
544b002b38fSJeremy Morse 
545b002b38fSJeremy Morse   void SetUp() override {
546b002b38fSJeremy Morse     M = parseIR(C, SpliceTestIR.c_str());
547b002b38fSJeremy Morse 
548b002b38fSJeremy Morse     BBEntry = &M->getFunction("f")->getEntryBlock();
549b002b38fSJeremy Morse     BBExit = BBEntry->getNextNode();
550b002b38fSJeremy Morse 
551b002b38fSJeremy Morse     Dest = BBExit->begin();
552b002b38fSJeremy Morse     First = BBEntry->begin();
553b002b38fSJeremy Morse     Last = BBEntry->getTerminator()->getIterator();
554b002b38fSJeremy Morse     BInst = &*First;
555b002b38fSJeremy Morse     Branch = &*Last;
556b002b38fSJeremy Morse     CInst = &*Dest;
557b002b38fSJeremy Morse 
558ffd08c77SStephen Tozer     DVRA =
55975dfa58eSStephen Tozer         cast<DbgVariableRecord>(&*BInst->DebugMarker->StoredDbgRecords.begin());
56075dfa58eSStephen Tozer     DVRB = cast<DbgVariableRecord>(
56175dfa58eSStephen Tozer         &*Branch->DebugMarker->StoredDbgRecords.begin());
562ffd08c77SStephen Tozer     DVRConst =
56375dfa58eSStephen Tozer         cast<DbgVariableRecord>(&*CInst->DebugMarker->StoredDbgRecords.begin());
564b002b38fSJeremy Morse   }
565b002b38fSJeremy Morse 
566ffd08c77SStephen Tozer   bool InstContainsDbgVariableRecord(Instruction *I, DbgVariableRecord *DVR) {
56715f3f446SStephen Tozer     for (DbgRecord &D : I->getDbgRecordRange()) {
568ffd08c77SStephen Tozer       if (&D == DVR) {
569b002b38fSJeremy Morse         // Confirm too that the links between the records are correct.
57075dfa58eSStephen Tozer         EXPECT_EQ(DVR->Marker, I->DebugMarker);
57175dfa58eSStephen Tozer         EXPECT_EQ(I->DebugMarker->MarkedInstr, I);
572b002b38fSJeremy Morse         return true;
573b002b38fSJeremy Morse       }
574b002b38fSJeremy Morse     }
575b002b38fSJeremy Morse     return false;
576b002b38fSJeremy Morse   }
577b002b38fSJeremy Morse 
578ffd08c77SStephen Tozer   bool CheckDVROrder(Instruction *I,
579ffd08c77SStephen Tozer                      SmallVector<DbgVariableRecord *> CheckVals) {
580ababa964SOrlando Cazalet-Hyams     SmallVector<DbgRecord *> Vals;
58115f3f446SStephen Tozer     for (DbgRecord &D : I->getDbgRecordRange())
582b002b38fSJeremy Morse       Vals.push_back(&D);
583b002b38fSJeremy Morse 
584b002b38fSJeremy Morse     EXPECT_EQ(Vals.size(), CheckVals.size());
585b002b38fSJeremy Morse     if (Vals.size() != CheckVals.size())
586b002b38fSJeremy Morse       return false;
587b002b38fSJeremy Morse 
588b002b38fSJeremy Morse     for (unsigned int I = 0; I < Vals.size(); ++I) {
589b002b38fSJeremy Morse       EXPECT_EQ(Vals[I], CheckVals[I]);
590b002b38fSJeremy Morse       // Provide another expectation failure to let us localise what goes wrong,
591b002b38fSJeremy Morse       // by returning a flag to the caller.
592b002b38fSJeremy Morse       if (Vals[I] != CheckVals[I])
593b002b38fSJeremy Morse         return false;
594b002b38fSJeremy Morse     }
595b002b38fSJeremy Morse     return true;
596b002b38fSJeremy Morse   }
597b002b38fSJeremy Morse };
598b002b38fSJeremy Morse 
599b002b38fSJeremy Morse TEST_F(DbgSpliceTest, DbgSpliceTest0) {
600b002b38fSJeremy Morse   Dest.setHeadBit(false);
601b002b38fSJeremy Morse   First.setHeadBit(false);
602b002b38fSJeremy Morse   Last.setTailBit(false);
603b002b38fSJeremy Morse 
604b002b38fSJeremy Morse   /*
605b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
606b002b38fSJeremy Morse BBEntry entry:
607ffd08c77SStephen Tozer DVRA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata
608ffd08c77SStephen Tozer !DIExpression()), !dbg !11 First     %b = add i16 %a, 1, !dbg !11 DVRB      call
609ffd08c77SStephen Tozer void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),
610ffd08c77SStephen Tozer !dbg !11 Last      br label %exit, !dbg !11
611b002b38fSJeremy Morse 
612b002b38fSJeremy Morse BBExit  exit:
613ffd08c77SStephen Tozer DVRConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata
614ffd08c77SStephen Tozer !DIExpression()), !dbg !11 Dest      %c = add i16 %b, 1, !dbg !11 ret i16 0,
615ffd08c77SStephen Tozer !dbg !11
616b002b38fSJeremy Morse         }
617b002b38fSJeremy Morse 
618b002b38fSJeremy Morse     Splice from First, not including leading dbg.value, to Last, including the
619b002b38fSJeremy Morse     trailing dbg.value. Place at Dest, between the constant dbg.value and %c.
620b002b38fSJeremy Morse     %b, and the following dbg.value, should move, to:
621b002b38fSJeremy Morse 
622b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
623b002b38fSJeremy Morse BBEntry entry:
624ffd08c77SStephen Tozer DVRA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata
625ffd08c77SStephen Tozer !DIExpression()), !dbg !11 Last      br label %exit, !dbg !11
626b002b38fSJeremy Morse 
627b002b38fSJeremy Morse BBExit  exit:
628ffd08c77SStephen Tozer DVRConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata
629ffd08c77SStephen Tozer !DIExpression()), !dbg !11 First     %b = add i16 %a, 1, !dbg !11 DVRB      call
630ffd08c77SStephen Tozer void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),
631ffd08c77SStephen Tozer !dbg !11 Dest      %c = add i16 %b, 1, !dbg !11 ret i16 0, !dbg !11
632b002b38fSJeremy Morse         }
633b002b38fSJeremy Morse 
634b002b38fSJeremy Morse 
635b002b38fSJeremy Morse   */
636b002b38fSJeremy Morse   BBExit->splice(Dest, BBEntry, First, Last);
637b002b38fSJeremy Morse   EXPECT_EQ(BInst->getParent(), BBExit);
638b002b38fSJeremy Morse   EXPECT_EQ(CInst->getParent(), BBExit);
639b002b38fSJeremy Morse   EXPECT_EQ(Branch->getParent(), BBEntry);
640b002b38fSJeremy Morse 
641ffd08c77SStephen Tozer   // DVRB: should be on Dest, in exit block.
642ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRB));
643b002b38fSJeremy Morse 
644ffd08c77SStephen Tozer   // DVRA, should have "fallen" onto the branch, remained in entry block.
645ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRA));
646b002b38fSJeremy Morse 
647ffd08c77SStephen Tozer   // DVRConst should be on the moved %b instruction.
648ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRConst));
649b002b38fSJeremy Morse }
650b002b38fSJeremy Morse 
651b002b38fSJeremy Morse TEST_F(DbgSpliceTest, DbgSpliceTest1) {
652b002b38fSJeremy Morse   Dest.setHeadBit(true);
653b002b38fSJeremy Morse   First.setHeadBit(false);
654b002b38fSJeremy Morse   Last.setTailBit(false);
655b002b38fSJeremy Morse 
656b002b38fSJeremy Morse   /*
657b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
658b002b38fSJeremy Morse BBEntry entry:
659ffd08c77SStephen Tozer DVRA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata
660ffd08c77SStephen Tozer !DIExpression()), !dbg !11 First     %b = add i16 %a, 1, !dbg !11 DVRB      call
661ffd08c77SStephen Tozer void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),
662ffd08c77SStephen Tozer !dbg !11 Last      br label %exit, !dbg !11
663b002b38fSJeremy Morse 
664b002b38fSJeremy Morse BBExit  exit:
665ffd08c77SStephen Tozer DVRConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata
666ffd08c77SStephen Tozer !DIExpression()), !dbg !11 Dest      %c = add i16 %b, 1, !dbg !11 ret i16 0,
667ffd08c77SStephen Tozer !dbg !11
668b002b38fSJeremy Morse         }
669b002b38fSJeremy Morse 
670b002b38fSJeremy Morse     Splice from First, not including leading dbg.value, to Last, including the
671b002b38fSJeremy Morse     trailing dbg.value. Place at the head of Dest, i.e. at the very start of
672b002b38fSJeremy Morse     BBExit, before any debug-info there. Becomes:
673b002b38fSJeremy Morse 
674b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
675b002b38fSJeremy Morse BBEntry entry:
676ffd08c77SStephen Tozer DVRA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata
677ffd08c77SStephen Tozer !DIExpression()), !dbg !11 Last      br label %exit, !dbg !11
678b002b38fSJeremy Morse 
679b002b38fSJeremy Morse BBExit  exit:
680b002b38fSJeremy Morse First     %b = add i16 %a, 1, !dbg !11
681ffd08c77SStephen Tozer DVRB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata
682ffd08c77SStephen Tozer !DIExpression()), !dbg !11 DVRConst  call void @llvm.dbg.value(metadata i16 0,
683ffd08c77SStephen Tozer metadata !9, metadata !DIExpression()), !dbg !11 Dest      %c = add i16 %b, 1,
684ffd08c77SStephen Tozer !dbg !11 ret i16 0, !dbg !11
685b002b38fSJeremy Morse         }
686b002b38fSJeremy Morse 
687b002b38fSJeremy Morse 
688b002b38fSJeremy Morse   */
689b002b38fSJeremy Morse   BBExit->splice(Dest, BBEntry, First, Last);
690b002b38fSJeremy Morse   EXPECT_EQ(BInst->getParent(), BBExit);
691b002b38fSJeremy Morse   EXPECT_EQ(CInst->getParent(), BBExit);
692b002b38fSJeremy Morse   EXPECT_EQ(Branch->getParent(), BBEntry);
693b002b38fSJeremy Morse 
694ffd08c77SStephen Tozer   // DVRB: should be on CInst, in exit block.
695ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRB));
696b002b38fSJeremy Morse 
697ffd08c77SStephen Tozer   // DVRA, should have "fallen" onto the branch, remained in entry block.
698ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRA));
699b002b38fSJeremy Morse 
700ffd08c77SStephen Tozer   // DVRConst should be behind / after the moved instructions, remain on CInst.
701ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRConst));
702b002b38fSJeremy Morse 
703ffd08c77SStephen Tozer   // Order of DVRB and DVRConst should be thus:
704ffd08c77SStephen Tozer   EXPECT_TRUE(CheckDVROrder(CInst, {DVRB, DVRConst}));
705b002b38fSJeremy Morse }
706b002b38fSJeremy Morse 
707b002b38fSJeremy Morse TEST_F(DbgSpliceTest, DbgSpliceTest2) {
708b002b38fSJeremy Morse   Dest.setHeadBit(false);
709b002b38fSJeremy Morse   First.setHeadBit(true);
710b002b38fSJeremy Morse   Last.setTailBit(false);
711b002b38fSJeremy Morse 
712b002b38fSJeremy Morse   /*
713b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
714b002b38fSJeremy Morse BBEntry entry:
715ffd08c77SStephen Tozer DVRA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata
716ffd08c77SStephen Tozer !DIExpression()), !dbg !11 First     %b = add i16 %a, 1, !dbg !11 DVRB      call
717ffd08c77SStephen Tozer void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),
718ffd08c77SStephen Tozer !dbg !11 Last      br label %exit, !dbg !11
719b002b38fSJeremy Morse 
720b002b38fSJeremy Morse BBExit  exit:
721ffd08c77SStephen Tozer DVRConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata
722ffd08c77SStephen Tozer !DIExpression()), !dbg !11 Dest      %c = add i16 %b, 1, !dbg !11 ret i16 0,
723ffd08c77SStephen Tozer !dbg !11
724b002b38fSJeremy Morse         }
725b002b38fSJeremy Morse 
726b002b38fSJeremy Morse     Splice from head of First, which includes the leading dbg.value, to Last,
727b002b38fSJeremy Morse     including the trailing dbg.value. Place in front of Dest, but after any
728b002b38fSJeremy Morse     debug-info there. Becomes:
729b002b38fSJeremy Morse 
730b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
731b002b38fSJeremy Morse BBEntry entry:
732b002b38fSJeremy Morse Last      br label %exit, !dbg !11
733b002b38fSJeremy Morse 
734b002b38fSJeremy Morse BBExit  exit:
735ffd08c77SStephen Tozer DVRConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata
736ffd08c77SStephen Tozer !DIExpression()), !dbg !11 DVRA      call void @llvm.dbg.value(metadata i16 %a,
737ffd08c77SStephen Tozer metadata !9, metadata !DIExpression()), !dbg !11 First     %b = add i16 %a, 1,
738ffd08c77SStephen Tozer !dbg !11 DVRB      call void @llvm.dbg.value(metadata i16 %b, metadata !9,
739ffd08c77SStephen Tozer metadata !DIExpression()), !dbg !11 Dest      %c = add i16 %b, 1, !dbg !11 ret
740ffd08c77SStephen Tozer i16 0, !dbg !11
741b002b38fSJeremy Morse         }
742b002b38fSJeremy Morse 
743b002b38fSJeremy Morse 
744b002b38fSJeremy Morse   */
745b002b38fSJeremy Morse   BBExit->splice(Dest, BBEntry, First, Last);
746b002b38fSJeremy Morse   EXPECT_EQ(BInst->getParent(), BBExit);
747b002b38fSJeremy Morse   EXPECT_EQ(CInst->getParent(), BBExit);
748b002b38fSJeremy Morse 
749ffd08c77SStephen Tozer   // DVRB: should be on CInst, in exit block.
750ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRB));
751b002b38fSJeremy Morse 
752ffd08c77SStephen Tozer   // DVRA, should have transferred with the spliced instructions, remains on
753b002b38fSJeremy Morse   // the "b" inst.
754ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRA));
755b002b38fSJeremy Morse 
756ffd08c77SStephen Tozer   // DVRConst should be ahead of the moved instructions, ahead of BInst.
757ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRConst));
758b002b38fSJeremy Morse 
759ffd08c77SStephen Tozer   // Order of DVRA and DVRConst should be thus:
760ffd08c77SStephen Tozer   EXPECT_TRUE(CheckDVROrder(BInst, {DVRConst, DVRA}));
761b002b38fSJeremy Morse }
762b002b38fSJeremy Morse 
763b002b38fSJeremy Morse TEST_F(DbgSpliceTest, DbgSpliceTest3) {
764b002b38fSJeremy Morse   Dest.setHeadBit(true);
765b002b38fSJeremy Morse   First.setHeadBit(true);
766b002b38fSJeremy Morse   Last.setTailBit(false);
767b002b38fSJeremy Morse 
768b002b38fSJeremy Morse   /*
769b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
770b002b38fSJeremy Morse BBEntry entry:
771ffd08c77SStephen Tozer DVRA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata
772ffd08c77SStephen Tozer !DIExpression()), !dbg !11 First     %b = add i16 %a, 1, !dbg !11 DVRB      call
773ffd08c77SStephen Tozer void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),
774ffd08c77SStephen Tozer !dbg !11 Last      br label %exit, !dbg !11
775b002b38fSJeremy Morse 
776b002b38fSJeremy Morse BBExit  exit:
777ffd08c77SStephen Tozer DVRConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata
778ffd08c77SStephen Tozer !DIExpression()), !dbg !11 Dest      %c = add i16 %b, 1, !dbg !11 ret i16 0,
779ffd08c77SStephen Tozer !dbg !11
780b002b38fSJeremy Morse         }
781b002b38fSJeremy Morse 
782b002b38fSJeremy Morse     Splice from head of First, which includes the leading dbg.value, to Last,
783b002b38fSJeremy Morse     including the trailing dbg.value. Place at head of Dest, before any
784b002b38fSJeremy Morse     debug-info there. Becomes:
785b002b38fSJeremy Morse 
786b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
787b002b38fSJeremy Morse BBEntry entry:
788b002b38fSJeremy Morse Last      br label %exit, !dbg !11
789b002b38fSJeremy Morse 
790b002b38fSJeremy Morse BBExit  exit:
791ffd08c77SStephen Tozer DVRA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata
792ffd08c77SStephen Tozer !DIExpression()), !dbg !11 First     %b = add i16 %a, 1, !dbg !11 DVRB      call
793ffd08c77SStephen Tozer void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),
794ffd08c77SStephen Tozer !dbg !11 DVRConst  call void @llvm.dbg.value(metadata i16 0, metadata !9,
795ffd08c77SStephen Tozer metadata !DIExpression()), !dbg !11 Dest      %c = add i16 %b, 1, !dbg !11 ret
796ffd08c77SStephen Tozer i16 0, !dbg !11
797b002b38fSJeremy Morse         }
798b002b38fSJeremy Morse 
799b002b38fSJeremy Morse   */
800b002b38fSJeremy Morse   BBExit->splice(Dest, BBEntry, First, Last);
801b002b38fSJeremy Morse   EXPECT_EQ(BInst->getParent(), BBExit);
802b002b38fSJeremy Morse   EXPECT_EQ(CInst->getParent(), BBExit);
803b002b38fSJeremy Morse 
804ffd08c77SStephen Tozer   // DVRB: should be on CInst, in exit block.
805ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRB));
806b002b38fSJeremy Morse 
807ffd08c77SStephen Tozer   // DVRA, should have transferred with the spliced instructions, remains on
808b002b38fSJeremy Morse   // the "b" inst.
809ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRA));
810b002b38fSJeremy Morse 
811ffd08c77SStephen Tozer   // DVRConst should be behind the moved instructions, ahead of CInst.
812ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRConst));
813b002b38fSJeremy Morse 
814ffd08c77SStephen Tozer   // Order of DVRB and DVRConst should be thus:
815ffd08c77SStephen Tozer   EXPECT_TRUE(CheckDVROrder(CInst, {DVRB, DVRConst}));
816b002b38fSJeremy Morse }
817b002b38fSJeremy Morse 
818b002b38fSJeremy Morse TEST_F(DbgSpliceTest, DbgSpliceTest4) {
819b002b38fSJeremy Morse   Dest.setHeadBit(false);
820b002b38fSJeremy Morse   First.setHeadBit(false);
821b002b38fSJeremy Morse   Last.setTailBit(true);
822b002b38fSJeremy Morse 
823b002b38fSJeremy Morse   /*
824b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
825b002b38fSJeremy Morse BBEntry entry:
826ffd08c77SStephen Tozer DVRA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata
827ffd08c77SStephen Tozer !DIExpression()), !dbg !11 First     %b = add i16 %a, 1, !dbg !11 DVRB      call
828ffd08c77SStephen Tozer void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),
829ffd08c77SStephen Tozer !dbg !11 Last      br label %exit, !dbg !11
830b002b38fSJeremy Morse 
831b002b38fSJeremy Morse BBExit  exit:
832ffd08c77SStephen Tozer DVRConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata
833ffd08c77SStephen Tozer !DIExpression()), !dbg !11 Dest      %c = add i16 %b, 1, !dbg !11 ret i16 0,
834ffd08c77SStephen Tozer !dbg !11
835b002b38fSJeremy Morse         }
836b002b38fSJeremy Morse 
837b002b38fSJeremy Morse     Splice from First, not including the leading dbg.value, to Last, but NOT
838b002b38fSJeremy Morse     including the trailing dbg.value because the tail bit is set. Place at Dest,
839b002b38fSJeremy Morse     after any debug-info there. Becomes:
840b002b38fSJeremy Morse 
841b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
842b002b38fSJeremy Morse BBEntry entry:
843ffd08c77SStephen Tozer DVRA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata
844ffd08c77SStephen Tozer !DIExpression()), !dbg !11 DVRB      call void @llvm.dbg.value(metadata i16 %b,
845ffd08c77SStephen Tozer metadata !9, metadata !DIExpression()), !dbg !11 Last      br label %exit, !dbg
846ffd08c77SStephen Tozer !11
847b002b38fSJeremy Morse 
848b002b38fSJeremy Morse BBExit  exit:
849ffd08c77SStephen Tozer DVRConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata
850ffd08c77SStephen Tozer !DIExpression()), !dbg !11 First     %b = add i16 %a, 1, !dbg !11 Dest      %c =
851ffd08c77SStephen Tozer add i16 %b, 1, !dbg !11 ret i16 0, !dbg !11
852b002b38fSJeremy Morse         }
853b002b38fSJeremy Morse 
854b002b38fSJeremy Morse   */
855b002b38fSJeremy Morse   BBExit->splice(Dest, BBEntry, First, Last);
856b002b38fSJeremy Morse   EXPECT_EQ(BInst->getParent(), BBExit);
857b002b38fSJeremy Morse   EXPECT_EQ(CInst->getParent(), BBExit);
858b002b38fSJeremy Morse   EXPECT_EQ(Branch->getParent(), BBEntry);
859b002b38fSJeremy Morse 
860ffd08c77SStephen Tozer   // DVRB: should be on Branch as before, remain in entry block.
861ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRB));
862b002b38fSJeremy Morse 
863ffd08c77SStephen Tozer   // DVRA, should have remained in entry block, falls onto Branch inst.
864ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRA));
865b002b38fSJeremy Morse 
866ffd08c77SStephen Tozer   // DVRConst should be ahead of the moved instructions, BInst.
867ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRConst));
868b002b38fSJeremy Morse 
869ffd08c77SStephen Tozer   // Order of DVRA and DVRA should be thus:
870ffd08c77SStephen Tozer   EXPECT_TRUE(CheckDVROrder(Branch, {DVRA, DVRB}));
871b002b38fSJeremy Morse }
872b002b38fSJeremy Morse 
873b002b38fSJeremy Morse TEST_F(DbgSpliceTest, DbgSpliceTest5) {
874b002b38fSJeremy Morse   Dest.setHeadBit(true);
875b002b38fSJeremy Morse   First.setHeadBit(false);
876b002b38fSJeremy Morse   Last.setTailBit(true);
877b002b38fSJeremy Morse 
878b002b38fSJeremy Morse   /*
879b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
880b002b38fSJeremy Morse BBEntry entry:
881ffd08c77SStephen Tozer DVRA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata
882ffd08c77SStephen Tozer !DIExpression()), !dbg !11 First     %b = add i16 %a, 1, !dbg !11 DVRB      call
883ffd08c77SStephen Tozer void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),
884ffd08c77SStephen Tozer !dbg !11 Last      br label %exit, !dbg !11
885b002b38fSJeremy Morse 
886b002b38fSJeremy Morse BBExit  exit:
887ffd08c77SStephen Tozer DVRConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata
888ffd08c77SStephen Tozer !DIExpression()), !dbg !11 Dest      %c = add i16 %b, 1, !dbg !11 ret i16 0,
889ffd08c77SStephen Tozer !dbg !11
890b002b38fSJeremy Morse         }
891b002b38fSJeremy Morse 
892b002b38fSJeremy Morse     Splice from First, not including the leading dbg.value, to Last, but NOT
893b002b38fSJeremy Morse     including the trailing dbg.value because the tail bit is set. Place at head
894b002b38fSJeremy Morse     of Dest, before any debug-info there. Becomes:
895b002b38fSJeremy Morse 
896b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
897b002b38fSJeremy Morse BBEntry entry:
898ffd08c77SStephen Tozer DVRA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata
899ffd08c77SStephen Tozer !DIExpression()), !dbg !11 DVRB      call void @llvm.dbg.value(metadata i16 %b,
900ffd08c77SStephen Tozer metadata !9, metadata !DIExpression()), !dbg !11 Last      br label %exit, !dbg
901ffd08c77SStephen Tozer !11
902b002b38fSJeremy Morse 
903b002b38fSJeremy Morse BBExit  exit:
904b002b38fSJeremy Morse First     %b = add i16 %a, 1, !dbg !11
905ffd08c77SStephen Tozer DVRConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata
906ffd08c77SStephen Tozer !DIExpression()), !dbg !11 Dest      %c = add i16 %b, 1, !dbg !11 ret i16 0,
907ffd08c77SStephen Tozer !dbg !11
908b002b38fSJeremy Morse         }
909b002b38fSJeremy Morse 
910b002b38fSJeremy Morse   */
911b002b38fSJeremy Morse   BBExit->splice(Dest, BBEntry, First, Last);
912b002b38fSJeremy Morse   EXPECT_EQ(BInst->getParent(), BBExit);
913b002b38fSJeremy Morse   EXPECT_EQ(CInst->getParent(), BBExit);
914b002b38fSJeremy Morse   EXPECT_EQ(Branch->getParent(), BBEntry);
915b002b38fSJeremy Morse 
916ffd08c77SStephen Tozer   // DVRB: should be on Branch as before, remain in entry block.
917ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRB));
918b002b38fSJeremy Morse 
919ffd08c77SStephen Tozer   // DVRA, should have remained in entry block, falls onto Branch inst.
920ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRA));
921b002b38fSJeremy Morse 
922ffd08c77SStephen Tozer   // DVRConst should be behind of the moved instructions, on CInst.
923ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRConst));
924b002b38fSJeremy Morse 
925ffd08c77SStephen Tozer   // Order of DVRA and DVRB should be thus:
926ffd08c77SStephen Tozer   EXPECT_TRUE(CheckDVROrder(Branch, {DVRA, DVRB}));
927b002b38fSJeremy Morse }
928b002b38fSJeremy Morse 
929b002b38fSJeremy Morse TEST_F(DbgSpliceTest, DbgSpliceTest6) {
930b002b38fSJeremy Morse   Dest.setHeadBit(false);
931b002b38fSJeremy Morse   First.setHeadBit(true);
932b002b38fSJeremy Morse   Last.setTailBit(true);
933b002b38fSJeremy Morse 
934b002b38fSJeremy Morse   /*
935b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
936b002b38fSJeremy Morse BBEntry entry:
937ffd08c77SStephen Tozer DVRA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata
938ffd08c77SStephen Tozer !DIExpression()), !dbg !11 First     %b = add i16 %a, 1, !dbg !11 DVRB      call
939ffd08c77SStephen Tozer void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),
940ffd08c77SStephen Tozer !dbg !11 Last      br label %exit, !dbg !11
941b002b38fSJeremy Morse 
942b002b38fSJeremy Morse BBExit  exit:
943ffd08c77SStephen Tozer DVRConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata
944ffd08c77SStephen Tozer !DIExpression()), !dbg !11 Dest      %c = add i16 %b, 1, !dbg !11 ret i16 0,
945ffd08c77SStephen Tozer !dbg !11
946b002b38fSJeremy Morse         }
947b002b38fSJeremy Morse 
948b002b38fSJeremy Morse     Splice from First, including the leading dbg.value, to Last, but NOT
949b002b38fSJeremy Morse     including the trailing dbg.value because the tail bit is set. Place at Dest,
950b002b38fSJeremy Morse     after any debug-info there. Becomes:
951b002b38fSJeremy Morse 
952b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
953b002b38fSJeremy Morse BBEntry entry:
954ffd08c77SStephen Tozer DVRB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata
955ffd08c77SStephen Tozer !DIExpression()), !dbg !11 Last      br label %exit, !dbg !11
956b002b38fSJeremy Morse 
957b002b38fSJeremy Morse BBExit  exit:
958ffd08c77SStephen Tozer DVRConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata
959ffd08c77SStephen Tozer !DIExpression()), !dbg !11 DVRA      call void @llvm.dbg.value(metadata i16 %a,
960ffd08c77SStephen Tozer metadata !9, metadata !DIExpression()), !dbg !11 First     %b = add i16 %a, 1,
961ffd08c77SStephen Tozer !dbg !11 Dest      %c = add i16 %b, 1, !dbg !11 ret i16 0, !dbg !11
962b002b38fSJeremy Morse         }
963b002b38fSJeremy Morse 
964b002b38fSJeremy Morse   */
965b002b38fSJeremy Morse   BBExit->splice(Dest, BBEntry, First, Last);
966b002b38fSJeremy Morse   EXPECT_EQ(BInst->getParent(), BBExit);
967b002b38fSJeremy Morse   EXPECT_EQ(CInst->getParent(), BBExit);
968b002b38fSJeremy Morse   EXPECT_EQ(Branch->getParent(), BBEntry);
969b002b38fSJeremy Morse 
970ffd08c77SStephen Tozer   // DVRB: should be on Branch as before, remain in entry block.
971ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRB));
972b002b38fSJeremy Morse 
973ffd08c77SStephen Tozer   // DVRA, should have transferred to BBExit, on B inst.
974ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRA));
975b002b38fSJeremy Morse 
976ffd08c77SStephen Tozer   // DVRConst should be ahead of the moved instructions, on BInst.
977ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRConst));
978b002b38fSJeremy Morse 
979ffd08c77SStephen Tozer   // Order of DVRA and DVRConst should be thus:
980ffd08c77SStephen Tozer   EXPECT_TRUE(CheckDVROrder(BInst, {DVRConst, DVRA}));
981b002b38fSJeremy Morse }
982b002b38fSJeremy Morse 
983b002b38fSJeremy Morse TEST_F(DbgSpliceTest, DbgSpliceTest7) {
984b002b38fSJeremy Morse   Dest.setHeadBit(true);
985b002b38fSJeremy Morse   First.setHeadBit(true);
986b002b38fSJeremy Morse   Last.setTailBit(true);
987b002b38fSJeremy Morse 
988b002b38fSJeremy Morse   /*
989b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
990b002b38fSJeremy Morse BBEntry entry:
991ffd08c77SStephen Tozer DVRA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata
992ffd08c77SStephen Tozer !DIExpression()), !dbg !11 First     %b = add i16 %a, 1, !dbg !11 DVRB      call
993ffd08c77SStephen Tozer void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),
994ffd08c77SStephen Tozer !dbg !11 Last      br label %exit, !dbg !11
995b002b38fSJeremy Morse 
996b002b38fSJeremy Morse BBExit  exit:
997ffd08c77SStephen Tozer DVRConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata
998ffd08c77SStephen Tozer !DIExpression()), !dbg !11 Dest      %c = add i16 %b, 1, !dbg !11 ret i16 0,
999ffd08c77SStephen Tozer !dbg !11
1000b002b38fSJeremy Morse         }
1001b002b38fSJeremy Morse 
1002b002b38fSJeremy Morse     Splice from First, including the leading dbg.value, to Last, but NOT
1003b002b38fSJeremy Morse     including the trailing dbg.value because the tail bit is set. Place at head
1004b002b38fSJeremy Morse     of Dest, before any debug-info there. Becomes:
1005b002b38fSJeremy Morse 
1006b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
1007b002b38fSJeremy Morse BBEntry entry:
1008ffd08c77SStephen Tozer DVRB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata
1009ffd08c77SStephen Tozer !DIExpression()), !dbg !11 Last      br label %exit, !dbg !11
1010b002b38fSJeremy Morse 
1011b002b38fSJeremy Morse BBExit  exit:
1012ffd08c77SStephen Tozer DVRA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata
1013ffd08c77SStephen Tozer !DIExpression()), !dbg !11 First     %b = add i16 %a, 1, !dbg !11 DVRConst  call
1014ffd08c77SStephen Tozer void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()),
1015ffd08c77SStephen Tozer !dbg !11 Dest      %c = add i16 %b, 1, !dbg !11 ret i16 0, !dbg !11
1016b002b38fSJeremy Morse         }
1017b002b38fSJeremy Morse 
1018b002b38fSJeremy Morse   */
1019b002b38fSJeremy Morse   BBExit->splice(Dest, BBEntry, First, Last);
1020b002b38fSJeremy Morse   EXPECT_EQ(BInst->getParent(), BBExit);
1021b002b38fSJeremy Morse   EXPECT_EQ(CInst->getParent(), BBExit);
1022b002b38fSJeremy Morse   EXPECT_EQ(Branch->getParent(), BBEntry);
1023b002b38fSJeremy Morse 
1024ffd08c77SStephen Tozer   // DVRB: should be on Branch as before, remain in entry block.
1025ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRB));
1026b002b38fSJeremy Morse 
1027ffd08c77SStephen Tozer   // DVRA, should have transferred to BBExit, on B inst.
1028ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRA));
1029b002b38fSJeremy Morse 
1030ffd08c77SStephen Tozer   // DVRConst should be after of the moved instructions, on CInst.
1031ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRConst));
1032b002b38fSJeremy Morse }
1033b002b38fSJeremy Morse 
1034b002b38fSJeremy Morse // But wait, there's more! What if you splice a range that is empty, but
1035b002b38fSJeremy Morse // implicitly contains debug-info? In the dbg.value design for debug-info,
1036ffd08c77SStephen Tozer // this would be an explicit range, but in DbgVariableRecord debug-info, it
1037ffd08c77SStephen Tozer // isn't. Check that if we try to do that, with differing head-bit values, that
1038ffd08c77SStephen Tozer // DbgVariableRecords are transferred.
1039b002b38fSJeremy Morse // Test with empty transfers to Dest, with head bit set and not set.
1040b002b38fSJeremy Morse 
1041b002b38fSJeremy Morse TEST_F(DbgSpliceTest, DbgSpliceEmpty0) {
1042b002b38fSJeremy Morse   Dest.setHeadBit(false);
1043b002b38fSJeremy Morse   First.setHeadBit(false);
1044b002b38fSJeremy Morse   Last.setHeadBit(false);
1045b002b38fSJeremy Morse   /*
1046b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
1047b002b38fSJeremy Morse BBEntry entry:
1048ffd08c77SStephen Tozer DVRA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata
1049ffd08c77SStephen Tozer !DIExpression()), !dbg !11 First     %b = add i16 %a, 1, !dbg !11 DVRB      call
1050ffd08c77SStephen Tozer void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),
1051ffd08c77SStephen Tozer !dbg !11 Last      br label %exit, !dbg !11
1052b002b38fSJeremy Morse 
1053b002b38fSJeremy Morse BBExit  exit:
1054ffd08c77SStephen Tozer DVRConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata
1055ffd08c77SStephen Tozer !DIExpression()), !dbg !11 Dest      %c = add i16 %b, 1, !dbg !11 ret i16 0,
1056ffd08c77SStephen Tozer !dbg !11
1057b002b38fSJeremy Morse         }
1058b002b38fSJeremy Morse 
1059b002b38fSJeremy Morse     Splice from BBEntry.getFirstInsertionPt to First -- this implicitly is a
1060ffd08c77SStephen Tozer     splice of DVRA, but the iterators are pointing at the same instruction. The
1061b002b38fSJeremy Morse     only difference is the setting of the head bit. Becomes;
1062b002b38fSJeremy Morse 
1063b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
1064b002b38fSJeremy Morse First     %b = add i16 %a, 1, !dbg !11
1065ffd08c77SStephen Tozer DVRB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata
1066ffd08c77SStephen Tozer !DIExpression()), !dbg !11 Last      br label %exit, !dbg !11
1067b002b38fSJeremy Morse 
1068b002b38fSJeremy Morse BBExit  exit:
1069ffd08c77SStephen Tozer DVRConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata
1070ffd08c77SStephen Tozer !DIExpression()), !dbg !11 DVRA      call void @llvm.dbg.value(metadata i16 %a,
1071ffd08c77SStephen Tozer metadata !9, metadata !DIExpression()), !dbg !11 Dest      %c = add i16 %b, 1,
1072ffd08c77SStephen Tozer !dbg !11 ret i16 0, !dbg !11
1073b002b38fSJeremy Morse         }
1074b002b38fSJeremy Morse 
1075b002b38fSJeremy Morse   */
1076b002b38fSJeremy Morse   BBExit->splice(Dest, BBEntry, BBEntry->getFirstInsertionPt(), First);
1077b002b38fSJeremy Morse   EXPECT_EQ(BInst->getParent(), BBEntry);
1078b002b38fSJeremy Morse   EXPECT_EQ(CInst->getParent(), BBExit);
1079b002b38fSJeremy Morse   EXPECT_EQ(Branch->getParent(), BBEntry);
1080b002b38fSJeremy Morse 
1081ffd08c77SStephen Tozer   // DVRB: should be on Branch as before, remain in entry block.
1082ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRB));
1083b002b38fSJeremy Morse 
1084ffd08c77SStephen Tozer   // DVRA, should have transferred to BBExit, on C inst.
1085ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRA));
1086b002b38fSJeremy Morse 
1087ffd08c77SStephen Tozer   // DVRConst should be ahead of the moved DbgVariableRecord, on CInst.
1088ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRConst));
1089b002b38fSJeremy Morse 
1090ffd08c77SStephen Tozer   // Order of DVRA and DVRConst should be thus:
1091ffd08c77SStephen Tozer   EXPECT_TRUE(CheckDVROrder(CInst, {DVRConst, DVRA}));
1092b002b38fSJeremy Morse }
1093b002b38fSJeremy Morse 
1094b002b38fSJeremy Morse TEST_F(DbgSpliceTest, DbgSpliceEmpty1) {
1095b002b38fSJeremy Morse   Dest.setHeadBit(true);
1096b002b38fSJeremy Morse   First.setHeadBit(false);
1097b002b38fSJeremy Morse   Last.setHeadBit(false);
1098b002b38fSJeremy Morse   /*
1099b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
1100b002b38fSJeremy Morse BBEntry entry:
1101ffd08c77SStephen Tozer DVRA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata
1102ffd08c77SStephen Tozer !DIExpression()), !dbg !11 First     %b = add i16 %a, 1, !dbg !11 DVRB      call
1103ffd08c77SStephen Tozer void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),
1104ffd08c77SStephen Tozer !dbg !11 Last      br label %exit, !dbg !11
1105b002b38fSJeremy Morse 
1106b002b38fSJeremy Morse BBExit  exit:
1107ffd08c77SStephen Tozer DVRConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata
1108ffd08c77SStephen Tozer !DIExpression()), !dbg !11 Dest      %c = add i16 %b, 1, !dbg !11 ret i16 0,
1109ffd08c77SStephen Tozer !dbg !11
1110b002b38fSJeremy Morse         }
1111b002b38fSJeremy Morse 
1112b002b38fSJeremy Morse     Splice from BBEntry.getFirstInsertionPt to First -- this implicitly is a
1113ffd08c77SStephen Tozer     splice of DVRA, but the iterators are pointing at the same instruction. The
1114b002b38fSJeremy Morse     only difference is the setting of the head bit. Insert at head of Dest,
1115ffd08c77SStephen Tozer     i.e. before DVRConst. Becomes;
1116b002b38fSJeremy Morse 
1117b002b38fSJeremy Morse         define i16 @f(i16 %a) !dbg !6 {
1118b002b38fSJeremy Morse First     %b = add i16 %a, 1, !dbg !11
1119ffd08c77SStephen Tozer DVRB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata
1120ffd08c77SStephen Tozer !DIExpression()), !dbg !11 Last      br label %exit, !dbg !11
1121b002b38fSJeremy Morse 
1122b002b38fSJeremy Morse BBExit  exit:
1123ffd08c77SStephen Tozer DVRA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata
1124ffd08c77SStephen Tozer !DIExpression()), !dbg !11 DVRConst  call void @llvm.dbg.value(metadata i16 0,
1125ffd08c77SStephen Tozer metadata !9, metadata !DIExpression()), !dbg !11 Dest      %c = add i16 %b, 1,
1126ffd08c77SStephen Tozer !dbg !11 ret i16 0, !dbg !11
1127b002b38fSJeremy Morse         }
1128b002b38fSJeremy Morse 
1129b002b38fSJeremy Morse   */
1130b002b38fSJeremy Morse   BBExit->splice(Dest, BBEntry, BBEntry->getFirstInsertionPt(), First);
1131b002b38fSJeremy Morse   EXPECT_EQ(BInst->getParent(), BBEntry);
1132b002b38fSJeremy Morse   EXPECT_EQ(CInst->getParent(), BBExit);
1133b002b38fSJeremy Morse   EXPECT_EQ(Branch->getParent(), BBEntry);
1134b002b38fSJeremy Morse 
1135ffd08c77SStephen Tozer   // DVRB: should be on Branch as before, remain in entry block.
1136ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRB));
1137b002b38fSJeremy Morse 
1138ffd08c77SStephen Tozer   // DVRA, should have transferred to BBExit, on C inst.
1139ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRA));
1140b002b38fSJeremy Morse 
1141ffd08c77SStephen Tozer   // DVRConst should be ahead of the moved DbgVariableRecord, on CInst.
1142ffd08c77SStephen Tozer   EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRConst));
1143b002b38fSJeremy Morse 
1144ffd08c77SStephen Tozer   // Order of DVRA and DVRConst should be thus:
1145ffd08c77SStephen Tozer   EXPECT_TRUE(CheckDVROrder(CInst, {DVRA, DVRConst}));
1146b002b38fSJeremy Morse }
1147b002b38fSJeremy Morse 
1148ffd08c77SStephen Tozer // If we splice new instructions into a block with trailing DbgVariableRecords,
1149ffd08c77SStephen Tozer // then the trailing DbgVariableRecords should get flushed back out.
1150b002b38fSJeremy Morse TEST(BasicBlockDbgInfoTest, DbgSpliceTrailing) {
1151b002b38fSJeremy Morse   LLVMContext C;
1152b002b38fSJeremy Morse   std::unique_ptr<Module> M = parseIR(C, R"(
1153b002b38fSJeremy Morse     define i16 @f(i16 %a) !dbg !6 {
1154b002b38fSJeremy Morse     entry:
1155b002b38fSJeremy Morse       call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
1156b002b38fSJeremy Morse       br label %exit
1157b002b38fSJeremy Morse 
1158b002b38fSJeremy Morse     exit:
1159b002b38fSJeremy Morse       %b = add i16 %a, 1, !dbg !11
1160b002b38fSJeremy Morse       ret i16 0, !dbg !11
1161b002b38fSJeremy Morse     }
1162b002b38fSJeremy Morse     declare void @llvm.dbg.value(metadata, metadata, metadata) #0
1163b002b38fSJeremy Morse     attributes #0 = { nounwind readnone speculatable willreturn }
1164b002b38fSJeremy Morse 
1165b002b38fSJeremy Morse     !llvm.dbg.cu = !{!0}
1166b002b38fSJeremy Morse     !llvm.module.flags = !{!5}
1167b002b38fSJeremy Morse 
1168b002b38fSJeremy Morse     !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
1169b002b38fSJeremy Morse     !1 = !DIFile(filename: "t.ll", directory: "/")
1170b002b38fSJeremy Morse     !2 = !{}
1171b002b38fSJeremy Morse     !5 = !{i32 2, !"Debug Info Version", i32 3}
1172b002b38fSJeremy Morse     !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
1173b002b38fSJeremy Morse     !7 = !DISubroutineType(types: !2)
1174b002b38fSJeremy Morse     !8 = !{!9}
1175b002b38fSJeremy Morse     !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
1176b002b38fSJeremy Morse     !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
1177b002b38fSJeremy Morse     !11 = !DILocation(line: 1, column: 1, scope: !6)
1178b002b38fSJeremy Morse )");
1179b002b38fSJeremy Morse 
1180b002b38fSJeremy Morse   BasicBlock &Entry = M->getFunction("f")->getEntryBlock();
1181b002b38fSJeremy Morse   BasicBlock &Exit = *Entry.getNextNode();
1182b002b38fSJeremy Morse 
1183ffd08c77SStephen Tozer   // Begin by forcing entry block to have dangling DbgVariableRecord.
1184b002b38fSJeremy Morse   Entry.getTerminator()->eraseFromParent();
118515f3f446SStephen Tozer   ASSERT_NE(Entry.getTrailingDbgRecords(), nullptr);
1186b002b38fSJeremy Morse   EXPECT_TRUE(Entry.empty());
1187b002b38fSJeremy Morse 
1188b002b38fSJeremy Morse   // Now transfer the entire contents of the exit block into the entry.
1189b002b38fSJeremy Morse   Entry.splice(Entry.end(), &Exit, Exit.begin(), Exit.end());
1190b002b38fSJeremy Morse 
1191ffd08c77SStephen Tozer   // The trailing DbgVariableRecord should have been placed at the front of
1192ffd08c77SStephen Tozer   // what's been spliced in.
1193b002b38fSJeremy Morse   Instruction *BInst = &*Entry.begin();
119475dfa58eSStephen Tozer   ASSERT_TRUE(BInst->DebugMarker);
119575dfa58eSStephen Tozer   EXPECT_EQ(BInst->DebugMarker->StoredDbgRecords.size(), 1u);
1196b002b38fSJeremy Morse }
1197b002b38fSJeremy Morse 
1198ffd08c77SStephen Tozer // When we remove instructions from the program, adjacent DbgVariableRecords
119975dfa58eSStephen Tozer // coalesce together into one DbgMarker. In "old" dbg.value mode you could
1200ffd08c77SStephen Tozer // re-insert the removed instruction back into the middle of a sequence of
1201ffd08c77SStephen Tozer // dbg.values. Test that this can be replicated correctly by DbgVariableRecords
12022ec0283cSJeremy Morse TEST(BasicBlockDbgInfoTest, RemoveInstAndReinsert) {
12032ec0283cSJeremy Morse   LLVMContext C;
12042ec0283cSJeremy Morse   std::unique_ptr<Module> M = parseIR(C, R"(
12052ec0283cSJeremy Morse     define i16 @f(i16 %a) !dbg !6 {
12062ec0283cSJeremy Morse     entry:
12072ec0283cSJeremy Morse       %qux = sub i16 %a, 0
12082ec0283cSJeremy Morse       call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
12092ec0283cSJeremy Morse       %foo = add i16 %a, %a
12102ec0283cSJeremy Morse       call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
12112ec0283cSJeremy Morse       ret i16 1
12122ec0283cSJeremy Morse     }
12132ec0283cSJeremy Morse     declare void @llvm.dbg.value(metadata, metadata, metadata)
12142ec0283cSJeremy Morse 
12152ec0283cSJeremy Morse     !llvm.dbg.cu = !{!0}
12162ec0283cSJeremy Morse     !llvm.module.flags = !{!5}
12172ec0283cSJeremy Morse 
12182ec0283cSJeremy Morse     !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
12192ec0283cSJeremy Morse     !1 = !DIFile(filename: "t.ll", directory: "/")
12202ec0283cSJeremy Morse     !2 = !{}
12212ec0283cSJeremy Morse     !5 = !{i32 2, !"Debug Info Version", i32 3}
12222ec0283cSJeremy Morse     !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
12232ec0283cSJeremy Morse     !7 = !DISubroutineType(types: !2)
12242ec0283cSJeremy Morse     !8 = !{!9}
12252ec0283cSJeremy Morse     !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
12262ec0283cSJeremy Morse     !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
12272ec0283cSJeremy Morse     !11 = !DILocation(line: 1, column: 1, scope: !6)
12282ec0283cSJeremy Morse )");
12292ec0283cSJeremy Morse 
12302ec0283cSJeremy Morse   BasicBlock &Entry = M->getFunction("f")->getEntryBlock();
12312ec0283cSJeremy Morse 
12322ec0283cSJeremy Morse   // Fetch the relevant instructions from the converted function.
12332ec0283cSJeremy Morse   Instruction *SubInst = &*Entry.begin();
12342ec0283cSJeremy Morse   ASSERT_TRUE(isa<BinaryOperator>(SubInst));
12352ec0283cSJeremy Morse   Instruction *AddInst = SubInst->getNextNode();
12362ec0283cSJeremy Morse   ASSERT_TRUE(isa<BinaryOperator>(AddInst));
12372ec0283cSJeremy Morse   Instruction *RetInst = AddInst->getNextNode();
12382ec0283cSJeremy Morse   ASSERT_TRUE(isa<ReturnInst>(RetInst));
12392ec0283cSJeremy Morse 
1240ffd08c77SStephen Tozer   // add and sub should both have one DbgVariableRecord on add and ret.
124115f3f446SStephen Tozer   EXPECT_FALSE(SubInst->hasDbgRecords());
124215f3f446SStephen Tozer   EXPECT_TRUE(AddInst->hasDbgRecords());
124315f3f446SStephen Tozer   EXPECT_TRUE(RetInst->hasDbgRecords());
124415f3f446SStephen Tozer   auto R1 = AddInst->getDbgRecordRange();
12452ec0283cSJeremy Morse   EXPECT_EQ(std::distance(R1.begin(), R1.end()), 1u);
124615f3f446SStephen Tozer   auto R2 = RetInst->getDbgRecordRange();
12472ec0283cSJeremy Morse   EXPECT_EQ(std::distance(R2.begin(), R2.end()), 1u);
12482ec0283cSJeremy Morse 
12492ec0283cSJeremy Morse   // The Supported (TM) code sequence for removing then reinserting insts
12502ec0283cSJeremy Morse   // after another instruction:
1251ffd08c77SStephen Tozer   std::optional<DbgVariableRecord::self_iterator> Pos =
12522ec0283cSJeremy Morse       AddInst->getDbgReinsertionPosition();
12532ec0283cSJeremy Morse   AddInst->removeFromParent();
12542ec0283cSJeremy Morse 
12552ec0283cSJeremy Morse   // We should have a re-insertion position.
12562ec0283cSJeremy Morse   ASSERT_TRUE(Pos);
1257ffd08c77SStephen Tozer   // Both DbgVariableRecords should now be attached to the ret inst.
125815f3f446SStephen Tozer   auto R3 = RetInst->getDbgRecordRange();
12592ec0283cSJeremy Morse   EXPECT_EQ(std::distance(R3.begin(), R3.end()), 2u);
12602ec0283cSJeremy Morse 
12612ec0283cSJeremy Morse   // Re-insert and re-insert.
1262*8e702735SJeremy Morse   AddInst->insertAfter(SubInst->getIterator());
126315f3f446SStephen Tozer   Entry.reinsertInstInDbgRecords(AddInst, Pos);
1264ffd08c77SStephen Tozer   // We should be back into a position of having one DbgVariableRecord on add
1265ffd08c77SStephen Tozer   // and ret.
126615f3f446SStephen Tozer   EXPECT_FALSE(SubInst->hasDbgRecords());
126715f3f446SStephen Tozer   EXPECT_TRUE(AddInst->hasDbgRecords());
126815f3f446SStephen Tozer   EXPECT_TRUE(RetInst->hasDbgRecords());
126915f3f446SStephen Tozer   auto R4 = AddInst->getDbgRecordRange();
12702ec0283cSJeremy Morse   EXPECT_EQ(std::distance(R4.begin(), R4.end()), 1u);
127115f3f446SStephen Tozer   auto R5 = RetInst->getDbgRecordRange();
12722ec0283cSJeremy Morse   EXPECT_EQ(std::distance(R5.begin(), R5.end()), 1u);
12732ec0283cSJeremy Morse }
12742ec0283cSJeremy Morse 
1275ffd08c77SStephen Tozer // Test instruction removal and re-insertion, this time with one
1276ffd08c77SStephen Tozer // DbgVariableRecord that should hop up one instruction.
1277ffd08c77SStephen Tozer TEST(BasicBlockDbgInfoTest, RemoveInstAndReinsertForOneDbgVariableRecord) {
12782ec0283cSJeremy Morse   LLVMContext C;
12792ec0283cSJeremy Morse   std::unique_ptr<Module> M = parseIR(C, R"(
12802ec0283cSJeremy Morse     define i16 @f(i16 %a) !dbg !6 {
12812ec0283cSJeremy Morse     entry:
12822ec0283cSJeremy Morse       %qux = sub i16 %a, 0
12832ec0283cSJeremy Morse       call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
12842ec0283cSJeremy Morse       %foo = add i16 %a, %a
12852ec0283cSJeremy Morse       ret i16 1
12862ec0283cSJeremy Morse     }
12872ec0283cSJeremy Morse     declare void @llvm.dbg.value(metadata, metadata, metadata)
12882ec0283cSJeremy Morse 
12892ec0283cSJeremy Morse     !llvm.dbg.cu = !{!0}
12902ec0283cSJeremy Morse     !llvm.module.flags = !{!5}
12912ec0283cSJeremy Morse 
12922ec0283cSJeremy Morse     !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
12932ec0283cSJeremy Morse     !1 = !DIFile(filename: "t.ll", directory: "/")
12942ec0283cSJeremy Morse     !2 = !{}
12952ec0283cSJeremy Morse     !5 = !{i32 2, !"Debug Info Version", i32 3}
12962ec0283cSJeremy Morse     !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
12972ec0283cSJeremy Morse     !7 = !DISubroutineType(types: !2)
12982ec0283cSJeremy Morse     !8 = !{!9}
12992ec0283cSJeremy Morse     !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
13002ec0283cSJeremy Morse     !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
13012ec0283cSJeremy Morse     !11 = !DILocation(line: 1, column: 1, scope: !6)
13022ec0283cSJeremy Morse )");
13032ec0283cSJeremy Morse 
13042ec0283cSJeremy Morse   BasicBlock &Entry = M->getFunction("f")->getEntryBlock();
13052ec0283cSJeremy Morse 
13062ec0283cSJeremy Morse   // Fetch the relevant instructions from the converted function.
13072ec0283cSJeremy Morse   Instruction *SubInst = &*Entry.begin();
13082ec0283cSJeremy Morse   ASSERT_TRUE(isa<BinaryOperator>(SubInst));
13092ec0283cSJeremy Morse   Instruction *AddInst = SubInst->getNextNode();
13102ec0283cSJeremy Morse   ASSERT_TRUE(isa<BinaryOperator>(AddInst));
13112ec0283cSJeremy Morse   Instruction *RetInst = AddInst->getNextNode();
13122ec0283cSJeremy Morse   ASSERT_TRUE(isa<ReturnInst>(RetInst));
13132ec0283cSJeremy Morse 
1314ffd08c77SStephen Tozer   // There should be one DbgVariableRecord.
131515f3f446SStephen Tozer   EXPECT_FALSE(SubInst->hasDbgRecords());
131615f3f446SStephen Tozer   EXPECT_TRUE(AddInst->hasDbgRecords());
131715f3f446SStephen Tozer   EXPECT_FALSE(RetInst->hasDbgRecords());
131815f3f446SStephen Tozer   auto R1 = AddInst->getDbgRecordRange();
13192ec0283cSJeremy Morse   EXPECT_EQ(std::distance(R1.begin(), R1.end()), 1u);
13202ec0283cSJeremy Morse 
13212ec0283cSJeremy Morse   // The Supported (TM) code sequence for removing then reinserting insts:
1322ffd08c77SStephen Tozer   std::optional<DbgVariableRecord::self_iterator> Pos =
13232ec0283cSJeremy Morse       AddInst->getDbgReinsertionPosition();
13242ec0283cSJeremy Morse   AddInst->removeFromParent();
13252ec0283cSJeremy Morse 
1326ffd08c77SStephen Tozer   // No re-insertion position as there were no DbgVariableRecords on the ret.
13272ec0283cSJeremy Morse   ASSERT_FALSE(Pos);
1328ffd08c77SStephen Tozer   // The single DbgVariableRecord should now be attached to the ret inst.
132915f3f446SStephen Tozer   EXPECT_TRUE(RetInst->hasDbgRecords());
133015f3f446SStephen Tozer   auto R2 = RetInst->getDbgRecordRange();
13312ec0283cSJeremy Morse   EXPECT_EQ(std::distance(R2.begin(), R2.end()), 1u);
13322ec0283cSJeremy Morse 
13332ec0283cSJeremy Morse   // Re-insert and re-insert.
1334*8e702735SJeremy Morse   AddInst->insertAfter(SubInst->getIterator());
133515f3f446SStephen Tozer   Entry.reinsertInstInDbgRecords(AddInst, Pos);
1336ffd08c77SStephen Tozer   // We should be back into a position of having one DbgVariableRecord on the
1337ffd08c77SStephen Tozer   // AddInst.
133815f3f446SStephen Tozer   EXPECT_FALSE(SubInst->hasDbgRecords());
133915f3f446SStephen Tozer   EXPECT_TRUE(AddInst->hasDbgRecords());
134015f3f446SStephen Tozer   EXPECT_FALSE(RetInst->hasDbgRecords());
134115f3f446SStephen Tozer   auto R3 = AddInst->getDbgRecordRange();
13422ec0283cSJeremy Morse   EXPECT_EQ(std::distance(R3.begin(), R3.end()), 1u);
13432ec0283cSJeremy Morse }
13442ec0283cSJeremy Morse 
134537f2f48cSJeremy Morse // Similar to the above, what if we splice into an empty block with debug-info,
134637f2f48cSJeremy Morse // with debug-info at the start of the moving range, that we intend to be
134737f2f48cSJeremy Morse // transferred. The dbg.value of %a should remain at the start, but come ahead
134837f2f48cSJeremy Morse // of the i16 0 dbg.value.
134937f2f48cSJeremy Morse TEST(BasicBlockDbgInfoTest, DbgSpliceToEmpty1) {
135037f2f48cSJeremy Morse   LLVMContext C;
135137f2f48cSJeremy Morse   std::unique_ptr<Module> M = parseIR(C, R"(
135237f2f48cSJeremy Morse     define i16 @f(i16 %a) !dbg !6 {
135337f2f48cSJeremy Morse     entry:
135437f2f48cSJeremy Morse       call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
135537f2f48cSJeremy Morse       br label %exit
135637f2f48cSJeremy Morse 
135737f2f48cSJeremy Morse     exit:
135837f2f48cSJeremy Morse       call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
135937f2f48cSJeremy Morse       %b = add i16 %a, 1, !dbg !11
136037f2f48cSJeremy Morse       call void @llvm.dbg.value(metadata i16 1, metadata !9, metadata !DIExpression()), !dbg !11
136137f2f48cSJeremy Morse       ret i16 0, !dbg !11
136237f2f48cSJeremy Morse     }
136337f2f48cSJeremy Morse     declare void @llvm.dbg.value(metadata, metadata, metadata) #0
136437f2f48cSJeremy Morse     attributes #0 = { nounwind readnone speculatable willreturn }
136537f2f48cSJeremy Morse 
136637f2f48cSJeremy Morse     !llvm.dbg.cu = !{!0}
136737f2f48cSJeremy Morse     !llvm.module.flags = !{!5}
136837f2f48cSJeremy Morse 
136937f2f48cSJeremy Morse     !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
137037f2f48cSJeremy Morse     !1 = !DIFile(filename: "t.ll", directory: "/")
137137f2f48cSJeremy Morse     !2 = !{}
137237f2f48cSJeremy Morse     !5 = !{i32 2, !"Debug Info Version", i32 3}
137337f2f48cSJeremy Morse     !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
137437f2f48cSJeremy Morse     !7 = !DISubroutineType(types: !2)
137537f2f48cSJeremy Morse     !8 = !{!9}
137637f2f48cSJeremy Morse     !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
137737f2f48cSJeremy Morse     !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
137837f2f48cSJeremy Morse     !11 = !DILocation(line: 1, column: 1, scope: !6)
137937f2f48cSJeremy Morse )");
138037f2f48cSJeremy Morse 
138137f2f48cSJeremy Morse   Function &F = *M->getFunction("f");
138237f2f48cSJeremy Morse   BasicBlock &Entry = F.getEntryBlock();
138337f2f48cSJeremy Morse   BasicBlock &Exit = *Entry.getNextNode();
138437f2f48cSJeremy Morse 
1385ffd08c77SStephen Tozer   // Begin by forcing entry block to have dangling DbgVariableRecord.
138637f2f48cSJeremy Morse   Entry.getTerminator()->eraseFromParent();
138715f3f446SStephen Tozer   ASSERT_NE(Entry.getTrailingDbgRecords(), nullptr);
138837f2f48cSJeremy Morse   EXPECT_TRUE(Entry.empty());
138937f2f48cSJeremy Morse 
139037f2f48cSJeremy Morse   // Now transfer the entire contents of the exit block into the entry. This
139137f2f48cSJeremy Morse   // includes both dbg.values.
139237f2f48cSJeremy Morse   Entry.splice(Entry.end(), &Exit, Exit.begin(), Exit.end());
139337f2f48cSJeremy Morse 
139437f2f48cSJeremy Morse   // We should now have two dbg.values on the first instruction, and they
139537f2f48cSJeremy Morse   // should be in the correct order of %a, then 0.
139637f2f48cSJeremy Morse   Instruction *BInst = &*Entry.begin();
139715f3f446SStephen Tozer   ASSERT_TRUE(BInst->hasDbgRecords());
139875dfa58eSStephen Tozer   EXPECT_EQ(BInst->DebugMarker->StoredDbgRecords.size(), 2u);
1399ffd08c77SStephen Tozer   SmallVector<DbgVariableRecord *, 2> DbgVariableRecords;
1400ffd08c77SStephen Tozer   for (DbgRecord &DVR : BInst->getDbgRecordRange())
1401ffd08c77SStephen Tozer     DbgVariableRecords.push_back(cast<DbgVariableRecord>(&DVR));
140237f2f48cSJeremy Morse 
1403ffd08c77SStephen Tozer   EXPECT_EQ(DbgVariableRecords[0]->getVariableLocationOp(0), F.getArg(0));
1404ffd08c77SStephen Tozer   Value *SecondDVRValue = DbgVariableRecords[1]->getVariableLocationOp(0);
1405ffd08c77SStephen Tozer   ASSERT_TRUE(isa<ConstantInt>(SecondDVRValue));
1406ffd08c77SStephen Tozer   EXPECT_EQ(cast<ConstantInt>(SecondDVRValue)->getZExtValue(), 0ull);
140737f2f48cSJeremy Morse 
1408ffd08c77SStephen Tozer   // No trailing DbgVariableRecords in the entry block now.
140915f3f446SStephen Tozer   EXPECT_EQ(Entry.getTrailingDbgRecords(), nullptr);
141037f2f48cSJeremy Morse }
141137f2f48cSJeremy Morse 
141237f2f48cSJeremy Morse // Similar test again, but this time: splice the contents of exit into entry,
141337f2f48cSJeremy Morse // with the intention of leaving the first dbg.value (i16 0) behind.
141437f2f48cSJeremy Morse TEST(BasicBlockDbgInfoTest, DbgSpliceToEmpty2) {
141537f2f48cSJeremy Morse   LLVMContext C;
141637f2f48cSJeremy Morse   std::unique_ptr<Module> M = parseIR(C, R"(
141737f2f48cSJeremy Morse     define i16 @f(i16 %a) !dbg !6 {
141837f2f48cSJeremy Morse     entry:
141937f2f48cSJeremy Morse       call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
142037f2f48cSJeremy Morse       br label %exit
142137f2f48cSJeremy Morse 
142237f2f48cSJeremy Morse     exit:
142337f2f48cSJeremy Morse       call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
142437f2f48cSJeremy Morse       %b = add i16 %a, 1, !dbg !11
142537f2f48cSJeremy Morse       call void @llvm.dbg.value(metadata i16 1, metadata !9, metadata !DIExpression()), !dbg !11
142637f2f48cSJeremy Morse       ret i16 0, !dbg !11
142737f2f48cSJeremy Morse     }
142837f2f48cSJeremy Morse     declare void @llvm.dbg.value(metadata, metadata, metadata) #0
142937f2f48cSJeremy Morse     attributes #0 = { nounwind readnone speculatable willreturn }
143037f2f48cSJeremy Morse 
143137f2f48cSJeremy Morse     !llvm.dbg.cu = !{!0}
143237f2f48cSJeremy Morse     !llvm.module.flags = !{!5}
143337f2f48cSJeremy Morse 
143437f2f48cSJeremy Morse     !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
143537f2f48cSJeremy Morse     !1 = !DIFile(filename: "t.ll", directory: "/")
143637f2f48cSJeremy Morse     !2 = !{}
143737f2f48cSJeremy Morse     !5 = !{i32 2, !"Debug Info Version", i32 3}
143837f2f48cSJeremy Morse     !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
143937f2f48cSJeremy Morse     !7 = !DISubroutineType(types: !2)
144037f2f48cSJeremy Morse     !8 = !{!9}
144137f2f48cSJeremy Morse     !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
144237f2f48cSJeremy Morse     !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
144337f2f48cSJeremy Morse     !11 = !DILocation(line: 1, column: 1, scope: !6)
144437f2f48cSJeremy Morse )");
144537f2f48cSJeremy Morse 
144637f2f48cSJeremy Morse   Function &F = *M->getFunction("f");
144737f2f48cSJeremy Morse   BasicBlock &Entry = F.getEntryBlock();
144837f2f48cSJeremy Morse   BasicBlock &Exit = *Entry.getNextNode();
144937f2f48cSJeremy Morse 
1450ffd08c77SStephen Tozer   // Begin by forcing entry block to have dangling DbgVariableRecord.
145137f2f48cSJeremy Morse   Entry.getTerminator()->eraseFromParent();
145215f3f446SStephen Tozer   ASSERT_NE(Entry.getTrailingDbgRecords(), nullptr);
145337f2f48cSJeremy Morse   EXPECT_TRUE(Entry.empty());
145437f2f48cSJeremy Morse 
145537f2f48cSJeremy Morse   // Now transfer into the entry block -- fetching the first instruction with
145637f2f48cSJeremy Morse   // begin and then calling getIterator clears the "head" bit, meaning that the
1457ffd08c77SStephen Tozer   // range to move will not include any leading DbgVariableRecords.
145837f2f48cSJeremy Morse   Entry.splice(Entry.end(), &Exit, Exit.begin()->getIterator(), Exit.end());
145937f2f48cSJeremy Morse 
146037f2f48cSJeremy Morse   // We should now have one dbg.values on the first instruction, %a.
146137f2f48cSJeremy Morse   Instruction *BInst = &*Entry.begin();
146215f3f446SStephen Tozer   ASSERT_TRUE(BInst->hasDbgRecords());
146375dfa58eSStephen Tozer   EXPECT_EQ(BInst->DebugMarker->StoredDbgRecords.size(), 1u);
1464ffd08c77SStephen Tozer   SmallVector<DbgVariableRecord *, 2> DbgVariableRecords;
1465ffd08c77SStephen Tozer   for (DbgRecord &DVR : BInst->getDbgRecordRange())
1466ffd08c77SStephen Tozer     DbgVariableRecords.push_back(cast<DbgVariableRecord>(&DVR));
146737f2f48cSJeremy Morse 
1468ffd08c77SStephen Tozer   EXPECT_EQ(DbgVariableRecords[0]->getVariableLocationOp(0), F.getArg(0));
1469ffd08c77SStephen Tozer   // No trailing DbgVariableRecords in the entry block now.
147015f3f446SStephen Tozer   EXPECT_EQ(Entry.getTrailingDbgRecords(), nullptr);
147137f2f48cSJeremy Morse 
147237f2f48cSJeremy Morse   // We should have nothing left in the exit block...
147337f2f48cSJeremy Morse   EXPECT_TRUE(Exit.empty());
1474ffd08c77SStephen Tozer   // ... except for some dangling DbgVariableRecords.
147515f3f446SStephen Tozer   EXPECT_NE(Exit.getTrailingDbgRecords(), nullptr);
147615f3f446SStephen Tozer   EXPECT_FALSE(Exit.getTrailingDbgRecords()->empty());
147715f3f446SStephen Tozer   Exit.getTrailingDbgRecords()->eraseFromParent();
147815f3f446SStephen Tozer   Exit.deleteTrailingDbgRecords();
147937f2f48cSJeremy Morse }
148033af16f5SJeremy Morse 
148133af16f5SJeremy Morse // What if we moveBefore end() -- there might be no debug-info there, in which
148233af16f5SJeremy Morse // case we shouldn't crash.
148333af16f5SJeremy Morse TEST(BasicBlockDbgInfoTest, DbgMoveToEnd) {
148433af16f5SJeremy Morse   LLVMContext C;
148533af16f5SJeremy Morse   std::unique_ptr<Module> M = parseIR(C, R"(
148633af16f5SJeremy Morse     define i16 @f(i16 %a) !dbg !6 {
148733af16f5SJeremy Morse     entry:
148833af16f5SJeremy Morse       br label %exit
148933af16f5SJeremy Morse 
149033af16f5SJeremy Morse     exit:
149133af16f5SJeremy Morse       ret i16 0, !dbg !11
149233af16f5SJeremy Morse     }
149333af16f5SJeremy Morse     declare void @llvm.dbg.value(metadata, metadata, metadata) #0
149433af16f5SJeremy Morse     attributes #0 = { nounwind readnone speculatable willreturn }
149533af16f5SJeremy Morse 
149633af16f5SJeremy Morse     !llvm.dbg.cu = !{!0}
149733af16f5SJeremy Morse     !llvm.module.flags = !{!5}
149833af16f5SJeremy Morse 
149933af16f5SJeremy Morse     !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
150033af16f5SJeremy Morse     !1 = !DIFile(filename: "t.ll", directory: "/")
150133af16f5SJeremy Morse     !2 = !{}
150233af16f5SJeremy Morse     !5 = !{i32 2, !"Debug Info Version", i32 3}
150333af16f5SJeremy Morse     !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
150433af16f5SJeremy Morse     !7 = !DISubroutineType(types: !2)
150533af16f5SJeremy Morse     !8 = !{!9}
150633af16f5SJeremy Morse     !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
150733af16f5SJeremy Morse     !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
150833af16f5SJeremy Morse     !11 = !DILocation(line: 1, column: 1, scope: !6)
150933af16f5SJeremy Morse )");
151033af16f5SJeremy Morse 
151133af16f5SJeremy Morse   Function &F = *M->getFunction("f");
151233af16f5SJeremy Morse   BasicBlock &Entry = F.getEntryBlock();
151333af16f5SJeremy Morse   BasicBlock &Exit = *Entry.getNextNode();
151433af16f5SJeremy Morse 
151533af16f5SJeremy Morse   // Move the return to the end of the entry block.
151633af16f5SJeremy Morse   Instruction *Br = Entry.getTerminator();
151733af16f5SJeremy Morse   Instruction *Ret = Exit.getTerminator();
151815f3f446SStephen Tozer   EXPECT_EQ(Entry.getTrailingDbgRecords(), nullptr);
151933af16f5SJeremy Morse   Ret->moveBefore(Entry, Entry.end());
152033af16f5SJeremy Morse   Br->eraseFromParent();
152133af16f5SJeremy Morse 
152233af16f5SJeremy Morse   // There should continue to not be any debug-info anywhere.
152315f3f446SStephen Tozer   EXPECT_EQ(Entry.getTrailingDbgRecords(), nullptr);
152415f3f446SStephen Tozer   EXPECT_EQ(Exit.getTrailingDbgRecords(), nullptr);
152515f3f446SStephen Tozer   EXPECT_FALSE(Ret->hasDbgRecords());
152633af16f5SJeremy Morse }
152733af16f5SJeremy Morse 
152843661a12SOrlando Cazalet-Hyams TEST(BasicBlockDbgInfoTest, CloneTrailingRecordsToEmptyBlock) {
152943661a12SOrlando Cazalet-Hyams   LLVMContext C;
153043661a12SOrlando Cazalet-Hyams   std::unique_ptr<Module> M = parseIR(C, R"(
153143661a12SOrlando Cazalet-Hyams     define i16 @foo(i16 %a) !dbg !6 {
153243661a12SOrlando Cazalet-Hyams     entry:
153343661a12SOrlando Cazalet-Hyams       %b = add i16 %a, 0
153443661a12SOrlando Cazalet-Hyams         #dbg_value(i16 %b, !9, !DIExpression(), !11)
153543661a12SOrlando Cazalet-Hyams       ret i16 0, !dbg !11
153643661a12SOrlando Cazalet-Hyams     }
153743661a12SOrlando Cazalet-Hyams 
153843661a12SOrlando Cazalet-Hyams     !llvm.dbg.cu = !{!0}
153943661a12SOrlando Cazalet-Hyams     !llvm.module.flags = !{!5}
154043661a12SOrlando Cazalet-Hyams 
154143661a12SOrlando Cazalet-Hyams     !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
154243661a12SOrlando Cazalet-Hyams     !1 = !DIFile(filename: "t.ll", directory: "/")
154343661a12SOrlando Cazalet-Hyams     !2 = !{}
154443661a12SOrlando Cazalet-Hyams     !5 = !{i32 2, !"Debug Info Version", i32 3}
154543661a12SOrlando Cazalet-Hyams     !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
154643661a12SOrlando Cazalet-Hyams     !7 = !DISubroutineType(types: !2)
154743661a12SOrlando Cazalet-Hyams     !8 = !{!9}
154843661a12SOrlando Cazalet-Hyams     !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
154943661a12SOrlando Cazalet-Hyams     !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
155043661a12SOrlando Cazalet-Hyams     !11 = !DILocation(line: 1, column: 1, scope: !6)
155143661a12SOrlando Cazalet-Hyams )");
155243661a12SOrlando Cazalet-Hyams   ASSERT_TRUE(M);
155343661a12SOrlando Cazalet-Hyams 
155443661a12SOrlando Cazalet-Hyams   Function *F = M->getFunction("foo");
155543661a12SOrlando Cazalet-Hyams   BasicBlock &BB = F->getEntryBlock();
155643661a12SOrlando Cazalet-Hyams   // Start with no trailing records.
155743661a12SOrlando Cazalet-Hyams   ASSERT_FALSE(BB.getTrailingDbgRecords());
155843661a12SOrlando Cazalet-Hyams 
155943661a12SOrlando Cazalet-Hyams   BasicBlock::iterator Ret = std::prev(BB.end());
156043661a12SOrlando Cazalet-Hyams   BasicBlock::iterator B = std::prev(Ret);
156143661a12SOrlando Cazalet-Hyams 
156243661a12SOrlando Cazalet-Hyams   // Delete terminator which has debug records: we now get trailing records.
156343661a12SOrlando Cazalet-Hyams   Ret->eraseFromParent();
156443661a12SOrlando Cazalet-Hyams   EXPECT_TRUE(BB.getTrailingDbgRecords());
156543661a12SOrlando Cazalet-Hyams 
156643661a12SOrlando Cazalet-Hyams   BasicBlock *NewBB = BasicBlock::Create(C, "NewBB", F);
156743661a12SOrlando Cazalet-Hyams   NewBB->splice(NewBB->end(), &BB, B, BB.end());
156843661a12SOrlando Cazalet-Hyams 
156943661a12SOrlando Cazalet-Hyams   // The trailing records should've been absorbed into NewBB.
157043661a12SOrlando Cazalet-Hyams   EXPECT_FALSE(BB.getTrailingDbgRecords());
157143661a12SOrlando Cazalet-Hyams   EXPECT_TRUE(NewBB->getTrailingDbgRecords());
15727ffe67c1SOrlando Cazalet-Hyams   if (DbgMarker *Trailing = NewBB->getTrailingDbgRecords()) {
15737ffe67c1SOrlando Cazalet-Hyams     EXPECT_EQ(llvm::range_size(Trailing->getDbgRecordRange()), 1u);
157443661a12SOrlando Cazalet-Hyams     // Drop the trailing records now, to prevent a cleanup assertion.
15757ffe67c1SOrlando Cazalet-Hyams     Trailing->eraseFromParent();
157643661a12SOrlando Cazalet-Hyams     NewBB->deleteTrailingDbgRecords();
157743661a12SOrlando Cazalet-Hyams   }
15787ffe67c1SOrlando Cazalet-Hyams }
157943661a12SOrlando Cazalet-Hyams 
1580b002b38fSJeremy Morse } // End anonymous namespace.
1581