1640 lines · cpp
1//===- llvm/unittest/IR/BasicBlockTest.cpp - BasicBlock unit tests --------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/IR/BasicBlock.h"10#include "llvm/IR/DebugInfo.h"11#include "llvm/ADT/STLExtras.h"12#include "llvm/AsmParser/Parser.h"13#include "llvm/IR/Function.h"14#include "llvm/IR/IRBuilder.h"15#include "llvm/IR/Instruction.h"16#include "llvm/IR/Instructions.h"17#include "llvm/IR/LLVMContext.h"18#include "llvm/IR/Module.h"19#include "llvm/IR/NoFolder.h"20#include "llvm/IR/Verifier.h"21#include "llvm/Support/SourceMgr.h"22#include "gmock/gmock-matchers.h"23#include "gtest/gtest.h"24#include <memory>25 26using namespace llvm;27 28static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {29 SMDiagnostic Err;30 std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);31 if (!Mod)32 Err.print("BasicBlockDbgInfoTest", errs());33 return Mod;34}35 36namespace {37 38// We can occasionally moveAfter an instruction so that it moves to the39// position that it already resides at. This is fine -- but gets complicated40// with dbg.value intrinsics. By moving an instruction, we can end up changing41// nothing but the location of debug-info intrinsics. That has to be modelled42// by DbgVariableRecords, the dbg.value replacement.43TEST(BasicBlockDbgInfoTest, InsertAfterSelf) {44 LLVMContext C;45 std::unique_ptr<Module> M = parseIR(C, R"(46 define i16 @f(i16 %a) !dbg !6 {47 call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !1148 %b = add i16 %a, 1, !dbg !1149 call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !1150 %c = add i16 %b, 1, !dbg !1151 ret i16 0, !dbg !1152 }53 declare void @llvm.dbg.value(metadata, metadata, metadata) #054 attributes #0 = { nounwind readnone speculatable willreturn }55 56 !llvm.dbg.cu = !{!0}57 !llvm.module.flags = !{!5}58 59 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)60 !1 = !DIFile(filename: "t.ll", directory: "/")61 !2 = !{}62 !5 = !{i32 2, !"Debug Info Version", i32 3}63 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)64 !7 = !DISubroutineType(types: !2)65 !8 = !{!9}66 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)67 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)68 !11 = !DILocation(line: 1, column: 1, scope: !6)69)");70 71 // Fetch the entry block.72 BasicBlock &BB = M->getFunction("f")->getEntryBlock();73 74 Instruction *Inst1 = &*BB.begin();75 Instruction *Inst2 = &*std::next(BB.begin());76 Instruction *RetInst = &*std::next(Inst2->getIterator());77 EXPECT_TRUE(Inst1->hasDbgRecords());78 EXPECT_TRUE(Inst2->hasDbgRecords());79 EXPECT_FALSE(RetInst->hasDbgRecords());80 81 // If we move Inst2 to be after Inst1, then it comes _immediately_ after. Were82 // we in dbg.value form we would then have:83 // dbg.value84 // %b = add85 // %c = add86 // dbg.value87 // Check that this is replicated by DbgVariableRecords.88 Inst2->moveAfter(Inst1);89 90 // Inst1 should only have one DbgVariableRecord on it.91 EXPECT_TRUE(Inst1->hasDbgRecords());92 auto Range1 = Inst1->getDbgRecordRange();93 EXPECT_EQ(std::distance(Range1.begin(), Range1.end()), 1u);94 // Inst2 should have none.95 EXPECT_FALSE(Inst2->hasDbgRecords());96 // While the return inst should now have one on it.97 EXPECT_TRUE(RetInst->hasDbgRecords());98 auto Range2 = RetInst->getDbgRecordRange();99 EXPECT_EQ(std::distance(Range2.begin(), Range2.end()), 1u);100}101 102TEST(BasicBlockDbgInfoTest, SplitBasicBlockBefore) {103 LLVMContext C;104 std::unique_ptr<Module> M = parseIR(C, R"---(105 define dso_local void @func() #0 !dbg !10 {106 %1 = alloca i32, align 4107 tail call void @llvm.dbg.declare(metadata ptr %1, metadata !14, metadata !DIExpression()), !dbg !16108 store i32 2, ptr %1, align 4, !dbg !16109 ret void, !dbg !17110 }111 112 declare void @llvm.dbg.declare(metadata, metadata, metadata) #0113 114 attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }115 116 !llvm.dbg.cu = !{!0}117 !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}118 !llvm.ident = !{!9}119 120 !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "dummy", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)121 !1 = !DIFile(filename: "dummy", directory: "dummy")122 !2 = !{i32 7, !"Dwarf Version", i32 5}123 !3 = !{i32 2, !"Debug Info Version", i32 3}124 !4 = !{i32 1, !"wchar_size", i32 4}125 !5 = !{i32 8, !"PIC Level", i32 2}126 !6 = !{i32 7, !"PIE Level", i32 2}127 !7 = !{i32 7, !"uwtable", i32 2}128 !8 = !{i32 7, !"frame-pointer", i32 2}129 !9 = !{!"dummy"}130 !10 = distinct !DISubprogram(name: "func", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !13)131 !11 = !DISubroutineType(types: !12)132 !12 = !{null}133 !13 = !{}134 !14 = !DILocalVariable(name: "a", scope: !10, file: !1, line: 2, type: !15)135 !15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)136 !16 = !DILocation(line: 2, column: 6, scope: !10)137 !17 = !DILocation(line: 3, column: 2, scope: !10)138 )---");139 ASSERT_TRUE(M);140 141 Function *F = M->getFunction("func");142 143 BasicBlock &BB = F->getEntryBlock();144 auto I = std::prev(BB.end(), 2); // store i32 2, ptr %1.145 BB.splitBasicBlockBefore(I, "before");146 147 BasicBlock &BBBefore = F->getEntryBlock();148 auto I2 = std::prev(BBBefore.end()); // br label %1 (new).149 ASSERT_TRUE(I2->hasDbgRecords());150}151 152TEST(BasicBlockDbgInfoTest, DropSourceAtomOnSplit) {153 LLVMContext C;154 std::unique_ptr<Module> M = parseIR(C, R"---(155 define dso_local void @func() !dbg !10 {156 %1 = alloca i32, align 4157 ret void, !dbg !DILocation(line: 3, column: 2, scope: !10, atomGroup: 1, atomRank: 1)158 }159 160 !llvm.dbg.cu = !{!0}161 !llvm.module.flags = !{!2, !3}162 163 !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "dummy", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)164 !1 = !DIFile(filename: "dummy", directory: "dummy")165 !2 = !{i32 7, !"Dwarf Version", i32 5}166 !3 = !{i32 2, !"Debug Info Version", i32 3}167 !10 = distinct !DISubprogram(name: "func", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !13, keyInstructions: true)168 !11 = !DISubroutineType(types: !12)169 !12 = !{null}170 !13 = !{}171 !14 = !DILocalVariable(name: "a", scope: !10, file: !1, line: 2, type: !15)172 !15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)173 )---");174 ASSERT_TRUE(M);175 176 Function *F = M->getFunction("func");177 178 // Test splitBasicBlockBefore.179 {180 BasicBlock &BB = F->back();181 // Split at `ret void`.182 BasicBlock *Before =183 BB.splitBasicBlockBefore(std::prev(BB.end(), 1), "before");184 const DebugLoc &BrToAfterDL = Before->getTerminator()->getDebugLoc();185 ASSERT_TRUE(BrToAfterDL);186 EXPECT_EQ(BrToAfterDL->getAtomGroup(), 0u);187 188 BasicBlock *After = Before->getSingleSuccessor();189 ASSERT_TRUE(After);190 const DebugLoc &OrigTerminatorDL = After->getTerminator()->getDebugLoc();191 ASSERT_TRUE(OrigTerminatorDL);192 EXPECT_EQ(OrigTerminatorDL->getAtomGroup(), 1u);193 }194 195 // Test splitBasicBlock.196 {197 BasicBlock &BB = F->back();198 // Split at `ret void`.199 BasicBlock *After = BB.splitBasicBlock(std::prev(BB.end(), 1), "before");200 201 const DebugLoc &OrigTerminatorDL = After->getTerminator()->getDebugLoc();202 ASSERT_TRUE(OrigTerminatorDL);203 EXPECT_EQ(OrigTerminatorDL->getAtomGroup(), 1u);204 205 BasicBlock *Before = After->getSinglePredecessor();206 ASSERT_TRUE(Before);207 const DebugLoc &BrToAfterDL = Before->getTerminator()->getDebugLoc();208 ASSERT_TRUE(BrToAfterDL);209 EXPECT_EQ(BrToAfterDL->getAtomGroup(), 0u);210 }211}212 213TEST(BasicBlockDbgInfoTest, MarkerOperations) {214 LLVMContext C;215 std::unique_ptr<Module> M = parseIR(C, R"(216 define i16 @f(i16 %a) !dbg !6 {217 call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11218 %b = add i16 %a, 1, !dbg !11219 call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11220 ret i16 0, !dbg !11221 }222 declare void @llvm.dbg.value(metadata, metadata, metadata) #0223 attributes #0 = { nounwind readnone speculatable willreturn }224 225 !llvm.dbg.cu = !{!0}226 !llvm.module.flags = !{!5}227 228 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)229 !1 = !DIFile(filename: "t.ll", directory: "/")230 !2 = !{}231 !5 = !{i32 2, !"Debug Info Version", i32 3}232 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)233 !7 = !DISubroutineType(types: !2)234 !8 = !{!9}235 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)236 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)237 !11 = !DILocation(line: 1, column: 1, scope: !6)238)");239 240 // Fetch the entry block,241 BasicBlock &BB = M->getFunction("f")->getEntryBlock();242 EXPECT_EQ(BB.size(), 2u);243 244 // Fetch out our two markers,245 Instruction *Instr1 = &*BB.begin();246 Instruction *Instr2 = Instr1->getNextNode();247 DbgMarker *Marker1 = Instr1->DebugMarker;248 DbgMarker *Marker2 = Instr2->DebugMarker;249 // There's no TrailingDbgRecords marker allocated yet.250 DbgMarker *EndMarker = nullptr;251 252 // Check that the "getMarker" utilities operate as expected.253 EXPECT_EQ(BB.getMarker(Instr1->getIterator()), Marker1);254 EXPECT_EQ(BB.getMarker(Instr2->getIterator()), Marker2);255 EXPECT_EQ(BB.getNextMarker(Instr1), Marker2);256 EXPECT_EQ(BB.getNextMarker(Instr2), EndMarker); // Is nullptr.257 258 // There should be two DbgVariableRecords,259 EXPECT_EQ(Marker1->StoredDbgRecords.size(), 1u);260 EXPECT_EQ(Marker2->StoredDbgRecords.size(), 1u);261 262 // Unlink them and try to re-insert them through the basic block.263 DbgRecord *DVR1 = &*Marker1->StoredDbgRecords.begin();264 DbgRecord *DVR2 = &*Marker2->StoredDbgRecords.begin();265 DVR1->removeFromParent();266 DVR2->removeFromParent();267 EXPECT_TRUE(Marker1->StoredDbgRecords.empty());268 EXPECT_TRUE(Marker2->StoredDbgRecords.empty());269 270 // This should appear in Marker1.271 BB.insertDbgRecordBefore(DVR1, BB.begin());272 EXPECT_EQ(Marker1->StoredDbgRecords.size(), 1u);273 EXPECT_EQ(DVR1, &*Marker1->StoredDbgRecords.begin());274 275 // This should attach to Marker2.276 BB.insertDbgRecordAfter(DVR2, &*BB.begin());277 EXPECT_EQ(Marker2->StoredDbgRecords.size(), 1u);278 EXPECT_EQ(DVR2, &*Marker2->StoredDbgRecords.begin());279 280 // Now, how about removing instructions? That should cause any281 // DbgVariableRecords to "fall down".282 Instr1->removeFromParent();283 Marker1 = nullptr;284 // DbgVariableRecords should now be in Marker2.285 EXPECT_EQ(BB.size(), 1u);286 EXPECT_EQ(Marker2->StoredDbgRecords.size(), 2u);287 // They should also be in the correct order.288 SmallVector<DbgRecord *, 2> DVRs(289 llvm::make_pointer_range(Marker2->getDbgRecordRange()));290 EXPECT_EQ(DVRs[0], DVR1);291 EXPECT_EQ(DVRs[1], DVR2);292 293 // If we remove the end instruction, the DbgVariableRecords should fall down294 // into the trailing marker.295 EXPECT_EQ(BB.getTrailingDbgRecords(), nullptr);296 Instr2->removeFromParent();297 EXPECT_TRUE(BB.empty());298 EndMarker = BB.getTrailingDbgRecords();299 ASSERT_NE(EndMarker, nullptr);300 EXPECT_EQ(EndMarker->StoredDbgRecords.size(), 2u);301 // Again, these should arrive in the correct order.302 303 DVRs.clear();304 for (DbgRecord &DVR : EndMarker->getDbgRecordRange())305 DVRs.push_back(&DVR);306 EXPECT_EQ(DVRs[0], DVR1);307 EXPECT_EQ(DVRs[1], DVR2);308 309 // Inserting a normal instruction at the beginning: shouldn't dislodge the310 // DbgVariableRecords. It's intended to not go at the start.311 Instr1->insertBefore(BB, BB.begin());312 EXPECT_EQ(EndMarker->StoredDbgRecords.size(), 2u);313 Instr1->removeFromParent();314 315 // Inserting at end(): should dislodge the DbgVariableRecords, if they were316 // dbg.values then they would sit "above" the new instruction.317 Instr1->insertBefore(BB, BB.end());318 EXPECT_EQ(Instr1->DebugMarker->StoredDbgRecords.size(), 2u);319 // We should de-allocate the trailing marker when something is inserted320 // at end().321 EXPECT_EQ(BB.getTrailingDbgRecords(), nullptr);322 323 // Remove Instr1: now the DbgVariableRecords will fall down again,324 Instr1->removeFromParent();325 EndMarker = BB.getTrailingDbgRecords();326 EXPECT_EQ(EndMarker->StoredDbgRecords.size(), 2u);327 328 // Inserting a terminator, however it's intended, should dislodge the329 // trailing DbgVariableRecords, as it's the clear intention of the caller that330 // this be the final instr in the block, and DbgVariableRecords aren't allowed331 // to live off the end forever.332 Instr2->insertBefore(BB, BB.begin());333 EXPECT_EQ(Instr2->DebugMarker->StoredDbgRecords.size(), 2u);334 EXPECT_EQ(BB.getTrailingDbgRecords(), nullptr);335 336 // Teardown,337 Instr1->insertBefore(BB, BB.begin());338}339 340TEST(BasicBlockDbgInfoTest, HeadBitOperations) {341 LLVMContext C;342 std::unique_ptr<Module> M = parseIR(C, R"(343 define i16 @f(i16 %a) !dbg !6 {344 %b = add i16 %a, 1, !dbg !11345 call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11346 %c = add i16 %a, 1, !dbg !11347 %d = add i16 %a, 1, !dbg !11348 ret i16 0, !dbg !11349 }350 declare void @llvm.dbg.value(metadata, metadata, metadata) #0351 attributes #0 = { nounwind readnone speculatable willreturn }352 353 !llvm.dbg.cu = !{!0}354 !llvm.module.flags = !{!5}355 356 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)357 !1 = !DIFile(filename: "t.ll", directory: "/")358 !2 = !{}359 !5 = !{i32 2, !"Debug Info Version", i32 3}360 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)361 !7 = !DISubroutineType(types: !2)362 !8 = !{!9}363 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)364 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)365 !11 = !DILocation(line: 1, column: 1, scope: !6)366)");367 368 // Test that the movement of debug-data when using moveBefore etc and369 // insertBefore etc are governed by the "head" bit of iterators.370 BasicBlock &BB = M->getFunction("f")->getEntryBlock();371 372 // Test that the head bit behaves as expected: it should be set when the373 // code wants the _start_ of the block, but not otherwise.374 EXPECT_TRUE(BB.getFirstInsertionPt().getHeadBit());375 BasicBlock::iterator BeginIt = BB.begin();376 EXPECT_TRUE(BeginIt.getHeadBit());377 // If you launder the instruction pointer through dereferencing and then378 // get the iterator again with getIterator, the head bit is lost. This is379 // deliberate: if you're calling getIterator, then you're requesting an380 // iterator for the position of _this_ instruction, not "the start of this381 // block".382 BasicBlock::iterator BeginIt2 = BeginIt->getIterator();383 EXPECT_FALSE(BeginIt2.getHeadBit());384 385 // Fetch some instruction pointers.386 Instruction *BInst = &*BeginIt;387 Instruction *CInst = BInst->getNextNode();388 Instruction *DInst = CInst->getNextNode();389 // CInst should have debug-info.390 ASSERT_TRUE(CInst->DebugMarker);391 EXPECT_FALSE(CInst->DebugMarker->StoredDbgRecords.empty());392 393 // If we move "c" to the start of the block, just normally, then the394 // DbgVariableRecords should fall down to "d".395 CInst->moveBefore(BB, BeginIt2);396 EXPECT_TRUE(!CInst->DebugMarker ||397 CInst->DebugMarker->StoredDbgRecords.empty());398 ASSERT_TRUE(DInst->DebugMarker);399 EXPECT_FALSE(DInst->DebugMarker->StoredDbgRecords.empty());400 401 // Wheras if we move D to the start of the block with moveBeforePreserving,402 // the DbgVariableRecords should move with it.403 DInst->moveBeforePreserving(BB, BB.begin());404 EXPECT_FALSE(DInst->DebugMarker->StoredDbgRecords.empty());405 EXPECT_EQ(&*BB.begin(), DInst);406 407 // Similarly, moveAfterPreserving "D" to "C" should move DbgVariableRecords408 // with "D".409 DInst->moveAfterPreserving(CInst);410 EXPECT_FALSE(DInst->DebugMarker->StoredDbgRecords.empty());411 412 // (move back to the start...)413 DInst->moveBeforePreserving(BB, BB.begin());414 415 // Current order of insts: "D -> C -> B -> Ret". DbgVariableRecords on "D".416 // If we move "C" to the beginning of the block, it should go before the417 // DbgVariableRecords. They'll stay on "D".418 CInst->moveBefore(BB, BB.begin());419 EXPECT_TRUE(!CInst->DebugMarker ||420 CInst->DebugMarker->StoredDbgRecords.empty());421 EXPECT_FALSE(DInst->DebugMarker->StoredDbgRecords.empty());422 EXPECT_EQ(&*BB.begin(), CInst);423 EXPECT_EQ(CInst->getNextNode(), DInst);424 425 // Move back.426 CInst->moveBefore(BInst->getIterator());427 EXPECT_EQ(&*BB.begin(), DInst);428 429 // Current order of insts: "D -> C -> B -> Ret". DbgVariableRecords on "D".430 // Now move CInst to the position of DInst, but using getIterator instead of431 // BasicBlock::begin. This signals that we want the "C" instruction to be432 // immediately before "D", with any DbgVariableRecords on "D" now moving to433 // "C". It's the equivalent of moving an instruction to the position between a434 // run of dbg.values and the next instruction.435 CInst->moveBefore(BB, DInst->getIterator());436 // CInst gains the DbgVariableRecords.437 EXPECT_TRUE(!DInst->DebugMarker ||438 DInst->DebugMarker->StoredDbgRecords.empty());439 EXPECT_FALSE(CInst->DebugMarker->StoredDbgRecords.empty());440 EXPECT_EQ(&*BB.begin(), CInst);441}442 443TEST(BasicBlockDbgInfoTest, InstrDbgAccess) {444 LLVMContext C;445 std::unique_ptr<Module> M = parseIR(C, R"(446 define i16 @f(i16 %a) !dbg !6 {447 %b = add i16 %a, 1, !dbg !11448 call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11449 %c = add i16 %a, 1, !dbg !11450 %d = add i16 %a, 1, !dbg !11451 ret i16 0, !dbg !11452 }453 declare void @llvm.dbg.value(metadata, metadata, metadata) #0454 attributes #0 = { nounwind readnone speculatable willreturn }455 456 !llvm.dbg.cu = !{!0}457 !llvm.module.flags = !{!5}458 459 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)460 !1 = !DIFile(filename: "t.ll", directory: "/")461 !2 = !{}462 !5 = !{i32 2, !"Debug Info Version", i32 3}463 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)464 !7 = !DISubroutineType(types: !2)465 !8 = !{!9}466 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)467 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)468 !11 = !DILocation(line: 1, column: 1, scope: !6)469)");470 471 // Check that DbgVariableRecords can be accessed from Instructions without472 // digging into the depths of DbgMarkers.473 BasicBlock &BB = M->getFunction("f")->getEntryBlock();474 475 Instruction *BInst = &*BB.begin();476 Instruction *CInst = BInst->getNextNode();477 Instruction *DInst = CInst->getNextNode();478 479 ASSERT_FALSE(BInst->DebugMarker);480 ASSERT_TRUE(CInst->DebugMarker);481 ASSERT_EQ(CInst->DebugMarker->StoredDbgRecords.size(), 1u);482 DbgRecord *DVR1 = &*CInst->DebugMarker->StoredDbgRecords.begin();483 ASSERT_TRUE(DVR1);484 EXPECT_FALSE(BInst->hasDbgRecords());485 486 // Clone DbgVariableRecords from one inst to another. Other arguments to clone487 // are tested in DbgMarker test.488 auto Range1 = BInst->cloneDebugInfoFrom(CInst);489 EXPECT_EQ(BInst->DebugMarker->StoredDbgRecords.size(), 1u);490 DbgRecord *DVR2 = &*BInst->DebugMarker->StoredDbgRecords.begin();491 EXPECT_EQ(std::distance(Range1.begin(), Range1.end()), 1u);492 EXPECT_EQ(&*Range1.begin(), DVR2);493 EXPECT_NE(DVR1, DVR2);494 495 // We should be able to get a range over exactly the same information.496 auto Range2 = BInst->getDbgRecordRange();497 EXPECT_EQ(Range1.begin(), Range2.begin());498 EXPECT_EQ(Range1.end(), Range2.end());499 500 // We should be able to query if there are DbgVariableRecords,501 EXPECT_TRUE(BInst->hasDbgRecords());502 EXPECT_TRUE(CInst->hasDbgRecords());503 EXPECT_FALSE(DInst->hasDbgRecords());504 505 // Dropping should be easy,506 BInst->dropDbgRecords();507 EXPECT_FALSE(BInst->hasDbgRecords());508 EXPECT_EQ(BInst->DebugMarker->StoredDbgRecords.size(), 0u);509 510 // And we should be able to drop individual DbgVariableRecords.511 CInst->dropOneDbgRecord(DVR1);512 EXPECT_FALSE(CInst->hasDbgRecords());513 EXPECT_EQ(CInst->DebugMarker->StoredDbgRecords.size(), 0u);514}515 516/* Let's recall the big illustration from BasicBlock::spliceDebugInfo:517 518 Dest519 |520 this-block: A----A----A ====A----A----A----A---A---A521 Src-block ++++B---B---B---B:::C522 | |523 First Last524 525 in all it's glory. Depending on the bit-configurations for the iterator head526 / tail bits on the three named iterators, there are eight ways for a splice to527 occur. To save the amount of thinking needed to pack this into one unit test,528 just test the same IR eight times with difference splices. The IR shall be529 thus:530 531 define i16 @f(i16 %a) !dbg !6 {532 entry:533 call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11534 %b = add i16 %a, 1, !dbg !11535 call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11536 br label %exit, !dbg !11537 538 exit:539 call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11540 %c = add i16 %b, 1, !dbg !11541 ret i16 0, !dbg !11542 }543 544 The iterators will be:545 Dest: exit block, "c" instruction.546 First: entry block, "b" instruction.547 Last: entry block, branch instruction.548 549 The numbered configurations will be:550 551 | Dest-Head | First-Head | Last-tail552 ----+----------------+----------------+------------553 0 | false | false | false554 1 | true | false | false555 2 | false | true | false556 3 | true | true | false557 4 | false | false | true558 5 | true | false | true559 6 | false | true | true560 7 | true | true | true561 562 Each numbered test scenario will also have a short explanation indicating what563 this bit configuration represents.564*/565 566static const std::string SpliceTestIR = R"(567 define i16 @f(i16 %a) !dbg !6 {568 call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11569 %b = add i16 %a, 1, !dbg !11570 call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11571 br label %exit, !dbg !11572 573 exit:574 call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11575 %c = add i16 %b, 1, !dbg !11576 ret i16 0, !dbg !11577 }578 declare void @llvm.dbg.value(metadata, metadata, metadata) #0579 attributes #0 = { nounwind readnone speculatable willreturn }580 581 !llvm.dbg.cu = !{!0}582 !llvm.module.flags = !{!5}583 584 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)585 !1 = !DIFile(filename: "t.ll", directory: "/")586 !2 = !{}587 !5 = !{i32 2, !"Debug Info Version", i32 3}588 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)589 !7 = !DISubroutineType(types: !2)590 !8 = !{!9}591 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)592 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)593 !11 = !DILocation(line: 1, column: 1, scope: !6)594)";595 596class DbgSpliceTest : public ::testing::Test {597protected:598 LLVMContext C;599 std::unique_ptr<Module> M;600 BasicBlock *BBEntry, *BBExit;601 BasicBlock::iterator Dest, First, Last;602 Instruction *BInst, *Branch, *CInst;603 DbgVariableRecord *DVRA, *DVRB, *DVRConst;604 605 void SetUp() override {606 M = parseIR(C, SpliceTestIR.c_str());607 608 BBEntry = &M->getFunction("f")->getEntryBlock();609 BBExit = BBEntry->getNextNode();610 611 Dest = BBExit->begin();612 First = BBEntry->begin();613 Last = BBEntry->getTerminator()->getIterator();614 BInst = &*First;615 Branch = &*Last;616 CInst = &*Dest;617 618 DVRA =619 cast<DbgVariableRecord>(&*BInst->DebugMarker->StoredDbgRecords.begin());620 DVRB = cast<DbgVariableRecord>(621 &*Branch->DebugMarker->StoredDbgRecords.begin());622 DVRConst =623 cast<DbgVariableRecord>(&*CInst->DebugMarker->StoredDbgRecords.begin());624 }625 626 bool InstContainsDbgVariableRecord(Instruction *I, DbgVariableRecord *DVR) {627 for (DbgRecord &D : I->getDbgRecordRange()) {628 if (&D == DVR) {629 // Confirm too that the links between the records are correct.630 EXPECT_EQ(DVR->Marker, I->DebugMarker);631 EXPECT_EQ(I->DebugMarker->MarkedInstr, I);632 return true;633 }634 }635 return false;636 }637 638 bool CheckDVROrder(Instruction *I,639 SmallVector<DbgVariableRecord *> CheckVals) {640 SmallVector<DbgRecord *> Vals(641 llvm::make_pointer_range(I->getDbgRecordRange()));642 643 EXPECT_EQ(Vals.size(), CheckVals.size());644 if (Vals.size() != CheckVals.size())645 return false;646 647 for (unsigned int I = 0; I < Vals.size(); ++I) {648 EXPECT_EQ(Vals[I], CheckVals[I]);649 // Provide another expectation failure to let us localise what goes wrong,650 // by returning a flag to the caller.651 if (Vals[I] != CheckVals[I])652 return false;653 }654 return true;655 }656};657 658TEST_F(DbgSpliceTest, DbgSpliceTest0) {659 Dest.setHeadBit(false);660 First.setHeadBit(false);661 Last.setTailBit(false);662 663 /*664 define i16 @f(i16 %a) !dbg !6 {665BBEntry entry:666DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata667!DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call668void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),669!dbg !11 Last br label %exit, !dbg !11670 671BBExit exit:672DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata673!DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0,674!dbg !11675 }676 677 Splice from First, not including leading dbg.value, to Last, including the678 trailing dbg.value. Place at Dest, between the constant dbg.value and %c.679 %b, and the following dbg.value, should move, to:680 681 define i16 @f(i16 %a) !dbg !6 {682BBEntry entry:683DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata684!DIExpression()), !dbg !11 Last br label %exit, !dbg !11685 686BBExit exit:687DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata688!DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call689void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),690!dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0, !dbg !11691 }692 693 694 */695 BBExit->splice(Dest, BBEntry, First, Last);696 EXPECT_EQ(BInst->getParent(), BBExit);697 EXPECT_EQ(CInst->getParent(), BBExit);698 EXPECT_EQ(Branch->getParent(), BBEntry);699 700 // DVRB: should be on Dest, in exit block.701 EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRB));702 703 // DVRA, should have "fallen" onto the branch, remained in entry block.704 EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRA));705 706 // DVRConst should be on the moved %b instruction.707 EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRConst));708}709 710TEST_F(DbgSpliceTest, DbgSpliceTest1) {711 Dest.setHeadBit(true);712 First.setHeadBit(false);713 Last.setTailBit(false);714 715 /*716 define i16 @f(i16 %a) !dbg !6 {717BBEntry entry:718DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata719!DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call720void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),721!dbg !11 Last br label %exit, !dbg !11722 723BBExit exit:724DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata725!DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0,726!dbg !11727 }728 729 Splice from First, not including leading dbg.value, to Last, including the730 trailing dbg.value. Place at the head of Dest, i.e. at the very start of731 BBExit, before any debug-info there. Becomes:732 733 define i16 @f(i16 %a) !dbg !6 {734BBEntry entry:735DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata736!DIExpression()), !dbg !11 Last br label %exit, !dbg !11737 738BBExit exit:739First %b = add i16 %a, 1, !dbg !11740DVRB call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata741!DIExpression()), !dbg !11 DVRConst call void @llvm.dbg.value(metadata i16 0,742metadata !9, metadata !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1,743!dbg !11 ret i16 0, !dbg !11744 }745 746 747 */748 BBExit->splice(Dest, BBEntry, First, Last);749 EXPECT_EQ(BInst->getParent(), BBExit);750 EXPECT_EQ(CInst->getParent(), BBExit);751 EXPECT_EQ(Branch->getParent(), BBEntry);752 753 // DVRB: should be on CInst, in exit block.754 EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRB));755 756 // DVRA, should have "fallen" onto the branch, remained in entry block.757 EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRA));758 759 // DVRConst should be behind / after the moved instructions, remain on CInst.760 EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRConst));761 762 // Order of DVRB and DVRConst should be thus:763 EXPECT_TRUE(CheckDVROrder(CInst, {DVRB, DVRConst}));764}765 766TEST_F(DbgSpliceTest, DbgSpliceTest2) {767 Dest.setHeadBit(false);768 First.setHeadBit(true);769 Last.setTailBit(false);770 771 /*772 define i16 @f(i16 %a) !dbg !6 {773BBEntry entry:774DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata775!DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call776void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),777!dbg !11 Last br label %exit, !dbg !11778 779BBExit exit:780DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata781!DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0,782!dbg !11783 }784 785 Splice from head of First, which includes the leading dbg.value, to Last,786 including the trailing dbg.value. Place in front of Dest, but after any787 debug-info there. Becomes:788 789 define i16 @f(i16 %a) !dbg !6 {790BBEntry entry:791Last br label %exit, !dbg !11792 793BBExit exit:794DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata795!DIExpression()), !dbg !11 DVRA call void @llvm.dbg.value(metadata i16 %a,796metadata !9, metadata !DIExpression()), !dbg !11 First %b = add i16 %a, 1,797!dbg !11 DVRB call void @llvm.dbg.value(metadata i16 %b, metadata !9,798metadata !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret799i16 0, !dbg !11800 }801 802 803 */804 BBExit->splice(Dest, BBEntry, First, Last);805 EXPECT_EQ(BInst->getParent(), BBExit);806 EXPECT_EQ(CInst->getParent(), BBExit);807 808 // DVRB: should be on CInst, in exit block.809 EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRB));810 811 // DVRA, should have transferred with the spliced instructions, remains on812 // the "b" inst.813 EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRA));814 815 // DVRConst should be ahead of the moved instructions, ahead of BInst.816 EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRConst));817 818 // Order of DVRA and DVRConst should be thus:819 EXPECT_TRUE(CheckDVROrder(BInst, {DVRConst, DVRA}));820}821 822TEST_F(DbgSpliceTest, DbgSpliceTest3) {823 Dest.setHeadBit(true);824 First.setHeadBit(true);825 Last.setTailBit(false);826 827 /*828 define i16 @f(i16 %a) !dbg !6 {829BBEntry entry:830DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata831!DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call832void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),833!dbg !11 Last br label %exit, !dbg !11834 835BBExit exit:836DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata837!DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0,838!dbg !11839 }840 841 Splice from head of First, which includes the leading dbg.value, to Last,842 including the trailing dbg.value. Place at head of Dest, before any843 debug-info there. Becomes:844 845 define i16 @f(i16 %a) !dbg !6 {846BBEntry entry:847Last br label %exit, !dbg !11848 849BBExit exit:850DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata851!DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call852void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),853!dbg !11 DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9,854metadata !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret855i16 0, !dbg !11856 }857 858 */859 BBExit->splice(Dest, BBEntry, First, Last);860 EXPECT_EQ(BInst->getParent(), BBExit);861 EXPECT_EQ(CInst->getParent(), BBExit);862 863 // DVRB: should be on CInst, in exit block.864 EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRB));865 866 // DVRA, should have transferred with the spliced instructions, remains on867 // the "b" inst.868 EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRA));869 870 // DVRConst should be behind the moved instructions, ahead of CInst.871 EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRConst));872 873 // Order of DVRB and DVRConst should be thus:874 EXPECT_TRUE(CheckDVROrder(CInst, {DVRB, DVRConst}));875}876 877TEST_F(DbgSpliceTest, DbgSpliceTest4) {878 Dest.setHeadBit(false);879 First.setHeadBit(false);880 Last.setTailBit(true);881 882 /*883 define i16 @f(i16 %a) !dbg !6 {884BBEntry entry:885DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata886!DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call887void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),888!dbg !11 Last br label %exit, !dbg !11889 890BBExit exit:891DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata892!DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0,893!dbg !11894 }895 896 Splice from First, not including the leading dbg.value, to Last, but NOT897 including the trailing dbg.value because the tail bit is set. Place at Dest,898 after any debug-info there. Becomes:899 900 define i16 @f(i16 %a) !dbg !6 {901BBEntry entry:902DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata903!DIExpression()), !dbg !11 DVRB call void @llvm.dbg.value(metadata i16 %b,904metadata !9, metadata !DIExpression()), !dbg !11 Last br label %exit, !dbg905!11906 907BBExit exit:908DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata909!DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 Dest %c =910add i16 %b, 1, !dbg !11 ret i16 0, !dbg !11911 }912 913 */914 BBExit->splice(Dest, BBEntry, First, Last);915 EXPECT_EQ(BInst->getParent(), BBExit);916 EXPECT_EQ(CInst->getParent(), BBExit);917 EXPECT_EQ(Branch->getParent(), BBEntry);918 919 // DVRB: should be on Branch as before, remain in entry block.920 EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRB));921 922 // DVRA, should have remained in entry block, falls onto Branch inst.923 EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRA));924 925 // DVRConst should be ahead of the moved instructions, BInst.926 EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRConst));927 928 // Order of DVRA and DVRA should be thus:929 EXPECT_TRUE(CheckDVROrder(Branch, {DVRA, DVRB}));930}931 932TEST_F(DbgSpliceTest, DbgSpliceTest5) {933 Dest.setHeadBit(true);934 First.setHeadBit(false);935 Last.setTailBit(true);936 937 /*938 define i16 @f(i16 %a) !dbg !6 {939BBEntry entry:940DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata941!DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call942void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),943!dbg !11 Last br label %exit, !dbg !11944 945BBExit exit:946DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata947!DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0,948!dbg !11949 }950 951 Splice from First, not including the leading dbg.value, to Last, but NOT952 including the trailing dbg.value because the tail bit is set. Place at head953 of Dest, before any debug-info there. Becomes:954 955 define i16 @f(i16 %a) !dbg !6 {956BBEntry entry:957DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata958!DIExpression()), !dbg !11 DVRB call void @llvm.dbg.value(metadata i16 %b,959metadata !9, metadata !DIExpression()), !dbg !11 Last br label %exit, !dbg960!11961 962BBExit exit:963First %b = add i16 %a, 1, !dbg !11964DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata965!DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0,966!dbg !11967 }968 969 */970 BBExit->splice(Dest, BBEntry, First, Last);971 EXPECT_EQ(BInst->getParent(), BBExit);972 EXPECT_EQ(CInst->getParent(), BBExit);973 EXPECT_EQ(Branch->getParent(), BBEntry);974 975 // DVRB: should be on Branch as before, remain in entry block.976 EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRB));977 978 // DVRA, should have remained in entry block, falls onto Branch inst.979 EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRA));980 981 // DVRConst should be behind of the moved instructions, on CInst.982 EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRConst));983 984 // Order of DVRA and DVRB should be thus:985 EXPECT_TRUE(CheckDVROrder(Branch, {DVRA, DVRB}));986}987 988TEST_F(DbgSpliceTest, DbgSpliceTest6) {989 Dest.setHeadBit(false);990 First.setHeadBit(true);991 Last.setTailBit(true);992 993 /*994 define i16 @f(i16 %a) !dbg !6 {995BBEntry entry:996DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata997!DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call998void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),999!dbg !11 Last br label %exit, !dbg !111000 1001BBExit exit:1002DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata1003!DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0,1004!dbg !111005 }1006 1007 Splice from First, including the leading dbg.value, to Last, but NOT1008 including the trailing dbg.value because the tail bit is set. Place at Dest,1009 after any debug-info there. Becomes:1010 1011 define i16 @f(i16 %a) !dbg !6 {1012BBEntry entry:1013DVRB call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata1014!DIExpression()), !dbg !11 Last br label %exit, !dbg !111015 1016BBExit exit:1017DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata1018!DIExpression()), !dbg !11 DVRA call void @llvm.dbg.value(metadata i16 %a,1019metadata !9, metadata !DIExpression()), !dbg !11 First %b = add i16 %a, 1,1020!dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0, !dbg !111021 }1022 1023 */1024 BBExit->splice(Dest, BBEntry, First, Last);1025 EXPECT_EQ(BInst->getParent(), BBExit);1026 EXPECT_EQ(CInst->getParent(), BBExit);1027 EXPECT_EQ(Branch->getParent(), BBEntry);1028 1029 // DVRB: should be on Branch as before, remain in entry block.1030 EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRB));1031 1032 // DVRA, should have transferred to BBExit, on B inst.1033 EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRA));1034 1035 // DVRConst should be ahead of the moved instructions, on BInst.1036 EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRConst));1037 1038 // Order of DVRA and DVRConst should be thus:1039 EXPECT_TRUE(CheckDVROrder(BInst, {DVRConst, DVRA}));1040}1041 1042TEST_F(DbgSpliceTest, DbgSpliceTest7) {1043 Dest.setHeadBit(true);1044 First.setHeadBit(true);1045 Last.setTailBit(true);1046 1047 /*1048 define i16 @f(i16 %a) !dbg !6 {1049BBEntry entry:1050DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata1051!DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call1052void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),1053!dbg !11 Last br label %exit, !dbg !111054 1055BBExit exit:1056DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata1057!DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0,1058!dbg !111059 }1060 1061 Splice from First, including the leading dbg.value, to Last, but NOT1062 including the trailing dbg.value because the tail bit is set. Place at head1063 of Dest, before any debug-info there. Becomes:1064 1065 define i16 @f(i16 %a) !dbg !6 {1066BBEntry entry:1067DVRB call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata1068!DIExpression()), !dbg !11 Last br label %exit, !dbg !111069 1070BBExit exit:1071DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata1072!DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRConst call1073void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()),1074!dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0, !dbg !111075 }1076 1077 */1078 BBExit->splice(Dest, BBEntry, First, Last);1079 EXPECT_EQ(BInst->getParent(), BBExit);1080 EXPECT_EQ(CInst->getParent(), BBExit);1081 EXPECT_EQ(Branch->getParent(), BBEntry);1082 1083 // DVRB: should be on Branch as before, remain in entry block.1084 EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRB));1085 1086 // DVRA, should have transferred to BBExit, on B inst.1087 EXPECT_TRUE(InstContainsDbgVariableRecord(BInst, DVRA));1088 1089 // DVRConst should be after of the moved instructions, on CInst.1090 EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRConst));1091}1092 1093// But wait, there's more! What if you splice a range that is empty, but1094// implicitly contains debug-info? In the dbg.value design for debug-info,1095// this would be an explicit range, but in DbgVariableRecord debug-info, it1096// isn't. Check that if we try to do that, with differing head-bit values, that1097// DbgVariableRecords are transferred.1098// Test with empty transfers to Dest, with head bit set and not set.1099 1100TEST_F(DbgSpliceTest, DbgSpliceEmpty0) {1101 Dest.setHeadBit(false);1102 First.setHeadBit(false);1103 Last.setHeadBit(false);1104 /*1105 define i16 @f(i16 %a) !dbg !6 {1106BBEntry entry:1107DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata1108!DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call1109void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),1110!dbg !11 Last br label %exit, !dbg !111111 1112BBExit exit:1113DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata1114!DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0,1115!dbg !111116 }1117 1118 Splice from BBEntry.getFirstInsertionPt to First -- this implicitly is a1119 splice of DVRA, but the iterators are pointing at the same instruction. The1120 only difference is the setting of the head bit. Becomes;1121 1122 define i16 @f(i16 %a) !dbg !6 {1123First %b = add i16 %a, 1, !dbg !111124DVRB call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata1125!DIExpression()), !dbg !11 Last br label %exit, !dbg !111126 1127BBExit exit:1128DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata1129!DIExpression()), !dbg !11 DVRA call void @llvm.dbg.value(metadata i16 %a,1130metadata !9, metadata !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1,1131!dbg !11 ret i16 0, !dbg !111132 }1133 1134 */1135 BBExit->splice(Dest, BBEntry, BBEntry->getFirstInsertionPt(), First);1136 EXPECT_EQ(BInst->getParent(), BBEntry);1137 EXPECT_EQ(CInst->getParent(), BBExit);1138 EXPECT_EQ(Branch->getParent(), BBEntry);1139 1140 // DVRB: should be on Branch as before, remain in entry block.1141 EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRB));1142 1143 // DVRA, should have transferred to BBExit, on C inst.1144 EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRA));1145 1146 // DVRConst should be ahead of the moved DbgVariableRecord, on CInst.1147 EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRConst));1148 1149 // Order of DVRA and DVRConst should be thus:1150 EXPECT_TRUE(CheckDVROrder(CInst, {DVRConst, DVRA}));1151}1152 1153TEST_F(DbgSpliceTest, DbgSpliceEmpty1) {1154 Dest.setHeadBit(true);1155 First.setHeadBit(false);1156 Last.setHeadBit(false);1157 /*1158 define i16 @f(i16 %a) !dbg !6 {1159BBEntry entry:1160DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata1161!DIExpression()), !dbg !11 First %b = add i16 %a, 1, !dbg !11 DVRB call1162void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()),1163!dbg !11 Last br label %exit, !dbg !111164 1165BBExit exit:1166DVRConst call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata1167!DIExpression()), !dbg !11 Dest %c = add i16 %b, 1, !dbg !11 ret i16 0,1168!dbg !111169 }1170 1171 Splice from BBEntry.getFirstInsertionPt to First -- this implicitly is a1172 splice of DVRA, but the iterators are pointing at the same instruction. The1173 only difference is the setting of the head bit. Insert at head of Dest,1174 i.e. before DVRConst. Becomes;1175 1176 define i16 @f(i16 %a) !dbg !6 {1177First %b = add i16 %a, 1, !dbg !111178DVRB call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata1179!DIExpression()), !dbg !11 Last br label %exit, !dbg !111180 1181BBExit exit:1182DVRA call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata1183!DIExpression()), !dbg !11 DVRConst call void @llvm.dbg.value(metadata i16 0,1184metadata !9, metadata !DIExpression()), !dbg !11 Dest %c = add i16 %b, 1,1185!dbg !11 ret i16 0, !dbg !111186 }1187 1188 */1189 BBExit->splice(Dest, BBEntry, BBEntry->getFirstInsertionPt(), First);1190 EXPECT_EQ(BInst->getParent(), BBEntry);1191 EXPECT_EQ(CInst->getParent(), BBExit);1192 EXPECT_EQ(Branch->getParent(), BBEntry);1193 1194 // DVRB: should be on Branch as before, remain in entry block.1195 EXPECT_TRUE(InstContainsDbgVariableRecord(Branch, DVRB));1196 1197 // DVRA, should have transferred to BBExit, on C inst.1198 EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRA));1199 1200 // DVRConst should be ahead of the moved DbgVariableRecord, on CInst.1201 EXPECT_TRUE(InstContainsDbgVariableRecord(CInst, DVRConst));1202 1203 // Order of DVRA and DVRConst should be thus:1204 EXPECT_TRUE(CheckDVROrder(CInst, {DVRA, DVRConst}));1205}1206 1207// If we splice new instructions into a block with trailing DbgVariableRecords,1208// then the trailing DbgVariableRecords should get flushed back out.1209TEST(BasicBlockDbgInfoTest, DbgSpliceTrailing) {1210 LLVMContext C;1211 std::unique_ptr<Module> M = parseIR(C, R"(1212 define i16 @f(i16 %a) !dbg !6 {1213 entry:1214 call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !111215 br label %exit1216 1217 exit:1218 %b = add i16 %a, 1, !dbg !111219 ret i16 0, !dbg !111220 }1221 declare void @llvm.dbg.value(metadata, metadata, metadata) #01222 attributes #0 = { nounwind readnone speculatable willreturn }1223 1224 !llvm.dbg.cu = !{!0}1225 !llvm.module.flags = !{!5}1226 1227 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)1228 !1 = !DIFile(filename: "t.ll", directory: "/")1229 !2 = !{}1230 !5 = !{i32 2, !"Debug Info Version", i32 3}1231 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)1232 !7 = !DISubroutineType(types: !2)1233 !8 = !{!9}1234 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)1235 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)1236 !11 = !DILocation(line: 1, column: 1, scope: !6)1237)");1238 1239 BasicBlock &Entry = M->getFunction("f")->getEntryBlock();1240 BasicBlock &Exit = *Entry.getNextNode();1241 1242 // Begin by forcing entry block to have dangling DbgVariableRecord.1243 Entry.getTerminator()->eraseFromParent();1244 ASSERT_NE(Entry.getTrailingDbgRecords(), nullptr);1245 EXPECT_TRUE(Entry.empty());1246 1247 // Now transfer the entire contents of the exit block into the entry.1248 Entry.splice(Entry.end(), &Exit, Exit.begin(), Exit.end());1249 1250 // The trailing DbgVariableRecord should have been placed at the front of1251 // what's been spliced in.1252 Instruction *BInst = &*Entry.begin();1253 ASSERT_TRUE(BInst->DebugMarker);1254 EXPECT_EQ(BInst->DebugMarker->StoredDbgRecords.size(), 1u);1255}1256 1257// When we remove instructions from the program, adjacent DbgVariableRecords1258// coalesce together into one DbgMarker. In "old" dbg.value mode you could1259// re-insert the removed instruction back into the middle of a sequence of1260// dbg.values. Test that this can be replicated correctly by DbgVariableRecords1261TEST(BasicBlockDbgInfoTest, RemoveInstAndReinsert) {1262 LLVMContext C;1263 std::unique_ptr<Module> M = parseIR(C, R"(1264 define i16 @f(i16 %a) !dbg !6 {1265 entry:1266 %qux = sub i16 %a, 01267 call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !111268 %foo = add i16 %a, %a1269 call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !111270 ret i16 11271 }1272 declare void @llvm.dbg.value(metadata, metadata, metadata)1273 1274 !llvm.dbg.cu = !{!0}1275 !llvm.module.flags = !{!5}1276 1277 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)1278 !1 = !DIFile(filename: "t.ll", directory: "/")1279 !2 = !{}1280 !5 = !{i32 2, !"Debug Info Version", i32 3}1281 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)1282 !7 = !DISubroutineType(types: !2)1283 !8 = !{!9}1284 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)1285 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)1286 !11 = !DILocation(line: 1, column: 1, scope: !6)1287)");1288 1289 BasicBlock &Entry = M->getFunction("f")->getEntryBlock();1290 1291 // Fetch the relevant instructions from the converted function.1292 Instruction *SubInst = &*Entry.begin();1293 ASSERT_TRUE(isa<BinaryOperator>(SubInst));1294 Instruction *AddInst = SubInst->getNextNode();1295 ASSERT_TRUE(isa<BinaryOperator>(AddInst));1296 Instruction *RetInst = AddInst->getNextNode();1297 ASSERT_TRUE(isa<ReturnInst>(RetInst));1298 1299 // add and sub should both have one DbgVariableRecord on add and ret.1300 EXPECT_FALSE(SubInst->hasDbgRecords());1301 EXPECT_TRUE(AddInst->hasDbgRecords());1302 EXPECT_TRUE(RetInst->hasDbgRecords());1303 auto R1 = AddInst->getDbgRecordRange();1304 EXPECT_EQ(std::distance(R1.begin(), R1.end()), 1u);1305 auto R2 = RetInst->getDbgRecordRange();1306 EXPECT_EQ(std::distance(R2.begin(), R2.end()), 1u);1307 1308 // The Supported (TM) code sequence for removing then reinserting insts1309 // after another instruction:1310 std::optional<DbgVariableRecord::self_iterator> Pos =1311 AddInst->getDbgReinsertionPosition();1312 AddInst->removeFromParent();1313 1314 // We should have a re-insertion position.1315 ASSERT_TRUE(Pos);1316 // Both DbgVariableRecords should now be attached to the ret inst.1317 auto R3 = RetInst->getDbgRecordRange();1318 EXPECT_EQ(std::distance(R3.begin(), R3.end()), 2u);1319 1320 // Re-insert and re-insert.1321 AddInst->insertAfter(SubInst->getIterator());1322 Entry.reinsertInstInDbgRecords(AddInst, Pos);1323 // We should be back into a position of having one DbgVariableRecord on add1324 // and ret.1325 EXPECT_FALSE(SubInst->hasDbgRecords());1326 EXPECT_TRUE(AddInst->hasDbgRecords());1327 EXPECT_TRUE(RetInst->hasDbgRecords());1328 auto R4 = AddInst->getDbgRecordRange();1329 EXPECT_EQ(std::distance(R4.begin(), R4.end()), 1u);1330 auto R5 = RetInst->getDbgRecordRange();1331 EXPECT_EQ(std::distance(R5.begin(), R5.end()), 1u);1332}1333 1334// Test instruction removal and re-insertion, this time with one1335// DbgVariableRecord that should hop up one instruction.1336TEST(BasicBlockDbgInfoTest, RemoveInstAndReinsertForOneDbgVariableRecord) {1337 LLVMContext C;1338 std::unique_ptr<Module> M = parseIR(C, R"(1339 define i16 @f(i16 %a) !dbg !6 {1340 entry:1341 %qux = sub i16 %a, 01342 call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !111343 %foo = add i16 %a, %a1344 ret i16 11345 }1346 declare void @llvm.dbg.value(metadata, metadata, metadata)1347 1348 !llvm.dbg.cu = !{!0}1349 !llvm.module.flags = !{!5}1350 1351 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)1352 !1 = !DIFile(filename: "t.ll", directory: "/")1353 !2 = !{}1354 !5 = !{i32 2, !"Debug Info Version", i32 3}1355 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)1356 !7 = !DISubroutineType(types: !2)1357 !8 = !{!9}1358 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)1359 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)1360 !11 = !DILocation(line: 1, column: 1, scope: !6)1361)");1362 1363 BasicBlock &Entry = M->getFunction("f")->getEntryBlock();1364 1365 // Fetch the relevant instructions from the converted function.1366 Instruction *SubInst = &*Entry.begin();1367 ASSERT_TRUE(isa<BinaryOperator>(SubInst));1368 Instruction *AddInst = SubInst->getNextNode();1369 ASSERT_TRUE(isa<BinaryOperator>(AddInst));1370 Instruction *RetInst = AddInst->getNextNode();1371 ASSERT_TRUE(isa<ReturnInst>(RetInst));1372 1373 // There should be one DbgVariableRecord.1374 EXPECT_FALSE(SubInst->hasDbgRecords());1375 EXPECT_TRUE(AddInst->hasDbgRecords());1376 EXPECT_FALSE(RetInst->hasDbgRecords());1377 auto R1 = AddInst->getDbgRecordRange();1378 EXPECT_EQ(std::distance(R1.begin(), R1.end()), 1u);1379 1380 // The Supported (TM) code sequence for removing then reinserting insts:1381 std::optional<DbgVariableRecord::self_iterator> Pos =1382 AddInst->getDbgReinsertionPosition();1383 AddInst->removeFromParent();1384 1385 // No re-insertion position as there were no DbgVariableRecords on the ret.1386 ASSERT_FALSE(Pos);1387 // The single DbgVariableRecord should now be attached to the ret inst.1388 EXPECT_TRUE(RetInst->hasDbgRecords());1389 auto R2 = RetInst->getDbgRecordRange();1390 EXPECT_EQ(std::distance(R2.begin(), R2.end()), 1u);1391 1392 // Re-insert and re-insert.1393 AddInst->insertAfter(SubInst->getIterator());1394 Entry.reinsertInstInDbgRecords(AddInst, Pos);1395 // We should be back into a position of having one DbgVariableRecord on the1396 // AddInst.1397 EXPECT_FALSE(SubInst->hasDbgRecords());1398 EXPECT_TRUE(AddInst->hasDbgRecords());1399 EXPECT_FALSE(RetInst->hasDbgRecords());1400 auto R3 = AddInst->getDbgRecordRange();1401 EXPECT_EQ(std::distance(R3.begin(), R3.end()), 1u);1402}1403 1404// Similar to the above, what if we splice into an empty block with debug-info,1405// with debug-info at the start of the moving range, that we intend to be1406// transferred. The dbg.value of %a should remain at the start, but come ahead1407// of the i16 0 dbg.value.1408TEST(BasicBlockDbgInfoTest, DbgSpliceToEmpty1) {1409 LLVMContext C;1410 std::unique_ptr<Module> M = parseIR(C, R"(1411 define i16 @f(i16 %a) !dbg !6 {1412 entry:1413 call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !111414 br label %exit1415 1416 exit:1417 call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !111418 %b = add i16 %a, 1, !dbg !111419 call void @llvm.dbg.value(metadata i16 1, metadata !9, metadata !DIExpression()), !dbg !111420 ret i16 0, !dbg !111421 }1422 declare void @llvm.dbg.value(metadata, metadata, metadata) #01423 attributes #0 = { nounwind readnone speculatable willreturn }1424 1425 !llvm.dbg.cu = !{!0}1426 !llvm.module.flags = !{!5}1427 1428 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)1429 !1 = !DIFile(filename: "t.ll", directory: "/")1430 !2 = !{}1431 !5 = !{i32 2, !"Debug Info Version", i32 3}1432 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)1433 !7 = !DISubroutineType(types: !2)1434 !8 = !{!9}1435 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)1436 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)1437 !11 = !DILocation(line: 1, column: 1, scope: !6)1438)");1439 1440 Function &F = *M->getFunction("f");1441 BasicBlock &Entry = F.getEntryBlock();1442 BasicBlock &Exit = *Entry.getNextNode();1443 1444 // Begin by forcing entry block to have dangling DbgVariableRecord.1445 Entry.getTerminator()->eraseFromParent();1446 ASSERT_NE(Entry.getTrailingDbgRecords(), nullptr);1447 EXPECT_TRUE(Entry.empty());1448 1449 // Now transfer the entire contents of the exit block into the entry. This1450 // includes both dbg.values.1451 Entry.splice(Entry.end(), &Exit, Exit.begin(), Exit.end());1452 1453 // We should now have two dbg.values on the first instruction, and they1454 // should be in the correct order of %a, then 0.1455 Instruction *BInst = &*Entry.begin();1456 ASSERT_TRUE(BInst->hasDbgRecords());1457 EXPECT_EQ(BInst->DebugMarker->StoredDbgRecords.size(), 2u);1458 SmallVector<DbgVariableRecord *, 2> DbgVariableRecords;1459 for (DbgRecord &DVR : BInst->getDbgRecordRange())1460 DbgVariableRecords.push_back(cast<DbgVariableRecord>(&DVR));1461 1462 EXPECT_EQ(DbgVariableRecords[0]->getVariableLocationOp(0), F.getArg(0));1463 Value *SecondDVRValue = DbgVariableRecords[1]->getVariableLocationOp(0);1464 ASSERT_TRUE(isa<ConstantInt>(SecondDVRValue));1465 EXPECT_EQ(cast<ConstantInt>(SecondDVRValue)->getZExtValue(), 0ull);1466 1467 // No trailing DbgVariableRecords in the entry block now.1468 EXPECT_EQ(Entry.getTrailingDbgRecords(), nullptr);1469}1470 1471// Similar test again, but this time: splice the contents of exit into entry,1472// with the intention of leaving the first dbg.value (i16 0) behind.1473TEST(BasicBlockDbgInfoTest, DbgSpliceToEmpty2) {1474 LLVMContext C;1475 std::unique_ptr<Module> M = parseIR(C, R"(1476 define i16 @f(i16 %a) !dbg !6 {1477 entry:1478 call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !111479 br label %exit1480 1481 exit:1482 call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !111483 %b = add i16 %a, 1, !dbg !111484 call void @llvm.dbg.value(metadata i16 1, metadata !9, metadata !DIExpression()), !dbg !111485 ret i16 0, !dbg !111486 }1487 declare void @llvm.dbg.value(metadata, metadata, metadata) #01488 attributes #0 = { nounwind readnone speculatable willreturn }1489 1490 !llvm.dbg.cu = !{!0}1491 !llvm.module.flags = !{!5}1492 1493 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)1494 !1 = !DIFile(filename: "t.ll", directory: "/")1495 !2 = !{}1496 !5 = !{i32 2, !"Debug Info Version", i32 3}1497 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)1498 !7 = !DISubroutineType(types: !2)1499 !8 = !{!9}1500 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)1501 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)1502 !11 = !DILocation(line: 1, column: 1, scope: !6)1503)");1504 1505 Function &F = *M->getFunction("f");1506 BasicBlock &Entry = F.getEntryBlock();1507 BasicBlock &Exit = *Entry.getNextNode();1508 1509 // Begin by forcing entry block to have dangling DbgVariableRecord.1510 Entry.getTerminator()->eraseFromParent();1511 ASSERT_NE(Entry.getTrailingDbgRecords(), nullptr);1512 EXPECT_TRUE(Entry.empty());1513 1514 // Now transfer into the entry block -- fetching the first instruction with1515 // begin and then calling getIterator clears the "head" bit, meaning that the1516 // range to move will not include any leading DbgVariableRecords.1517 Entry.splice(Entry.end(), &Exit, Exit.begin()->getIterator(), Exit.end());1518 1519 // We should now have one dbg.values on the first instruction, %a.1520 Instruction *BInst = &*Entry.begin();1521 ASSERT_TRUE(BInst->hasDbgRecords());1522 EXPECT_EQ(BInst->DebugMarker->StoredDbgRecords.size(), 1u);1523 SmallVector<DbgVariableRecord *, 2> DbgVariableRecords;1524 for (DbgRecord &DVR : BInst->getDbgRecordRange())1525 DbgVariableRecords.push_back(cast<DbgVariableRecord>(&DVR));1526 1527 EXPECT_EQ(DbgVariableRecords[0]->getVariableLocationOp(0), F.getArg(0));1528 // No trailing DbgVariableRecords in the entry block now.1529 EXPECT_EQ(Entry.getTrailingDbgRecords(), nullptr);1530 1531 // We should have nothing left in the exit block...1532 EXPECT_TRUE(Exit.empty());1533 // ... except for some dangling DbgVariableRecords.1534 EXPECT_NE(Exit.getTrailingDbgRecords(), nullptr);1535 EXPECT_FALSE(Exit.getTrailingDbgRecords()->empty());1536 Exit.getTrailingDbgRecords()->eraseFromParent();1537 Exit.deleteTrailingDbgRecords();1538}1539 1540// What if we moveBefore end() -- there might be no debug-info there, in which1541// case we shouldn't crash.1542TEST(BasicBlockDbgInfoTest, DbgMoveToEnd) {1543 LLVMContext C;1544 std::unique_ptr<Module> M = parseIR(C, R"(1545 define i16 @f(i16 %a) !dbg !6 {1546 entry:1547 br label %exit1548 1549 exit:1550 ret i16 0, !dbg !111551 }1552 declare void @llvm.dbg.value(metadata, metadata, metadata) #01553 attributes #0 = { nounwind readnone speculatable willreturn }1554 1555 !llvm.dbg.cu = !{!0}1556 !llvm.module.flags = !{!5}1557 1558 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)1559 !1 = !DIFile(filename: "t.ll", directory: "/")1560 !2 = !{}1561 !5 = !{i32 2, !"Debug Info Version", i32 3}1562 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)1563 !7 = !DISubroutineType(types: !2)1564 !8 = !{!9}1565 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)1566 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)1567 !11 = !DILocation(line: 1, column: 1, scope: !6)1568)");1569 1570 Function &F = *M->getFunction("f");1571 BasicBlock &Entry = F.getEntryBlock();1572 BasicBlock &Exit = *Entry.getNextNode();1573 1574 // Move the return to the end of the entry block.1575 Instruction *Br = Entry.getTerminator();1576 Instruction *Ret = Exit.getTerminator();1577 EXPECT_EQ(Entry.getTrailingDbgRecords(), nullptr);1578 Ret->moveBefore(Entry, Entry.end());1579 Br->eraseFromParent();1580 1581 // There should continue to not be any debug-info anywhere.1582 EXPECT_EQ(Entry.getTrailingDbgRecords(), nullptr);1583 EXPECT_EQ(Exit.getTrailingDbgRecords(), nullptr);1584 EXPECT_FALSE(Ret->hasDbgRecords());1585}1586 1587TEST(BasicBlockDbgInfoTest, CloneTrailingRecordsToEmptyBlock) {1588 LLVMContext C;1589 std::unique_ptr<Module> M = parseIR(C, R"(1590 define i16 @foo(i16 %a) !dbg !6 {1591 entry:1592 %b = add i16 %a, 01593 #dbg_value(i16 %b, !9, !DIExpression(), !11)1594 ret i16 0, !dbg !111595 }1596 1597 !llvm.dbg.cu = !{!0}1598 !llvm.module.flags = !{!5}1599 1600 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)1601 !1 = !DIFile(filename: "t.ll", directory: "/")1602 !2 = !{}1603 !5 = !{i32 2, !"Debug Info Version", i32 3}1604 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)1605 !7 = !DISubroutineType(types: !2)1606 !8 = !{!9}1607 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)1608 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)1609 !11 = !DILocation(line: 1, column: 1, scope: !6)1610)");1611 ASSERT_TRUE(M);1612 1613 Function *F = M->getFunction("foo");1614 BasicBlock &BB = F->getEntryBlock();1615 // Start with no trailing records.1616 ASSERT_FALSE(BB.getTrailingDbgRecords());1617 1618 BasicBlock::iterator Ret = std::prev(BB.end());1619 BasicBlock::iterator B = std::prev(Ret);1620 1621 // Delete terminator which has debug records: we now get trailing records.1622 Ret->eraseFromParent();1623 EXPECT_TRUE(BB.getTrailingDbgRecords());1624 1625 BasicBlock *NewBB = BasicBlock::Create(C, "NewBB", F);1626 NewBB->splice(NewBB->end(), &BB, B, BB.end());1627 1628 // The trailing records should've been absorbed into NewBB.1629 EXPECT_FALSE(BB.getTrailingDbgRecords());1630 EXPECT_TRUE(NewBB->getTrailingDbgRecords());1631 if (DbgMarker *Trailing = NewBB->getTrailingDbgRecords()) {1632 EXPECT_EQ(llvm::range_size(Trailing->getDbgRecordRange()), 1u);1633 // Drop the trailing records now, to prevent a cleanup assertion.1634 Trailing->eraseFromParent();1635 NewBB->deleteTrailingDbgRecords();1636 }1637}1638 1639} // End anonymous namespace.1640