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