1 //===- llvm/unittest/IR/DebugInfo.cpp - DebugInfo tests -------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/IR/DebugInfo.h" 10 #include "llvm/AsmParser/Parser.h" 11 #include "llvm/IR/DebugInfoMetadata.h" 12 #include "llvm/IR/IntrinsicInst.h" 13 #include "llvm/IR/LLVMContext.h" 14 #include "llvm/IR/Module.h" 15 #include "llvm/IR/Verifier.h" 16 #include "llvm/Support/SourceMgr.h" 17 #include "llvm/Transforms/Utils/Local.h" 18 #include "gtest/gtest.h" 19 20 using namespace llvm; 21 22 static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { 23 SMDiagnostic Err; 24 std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C); 25 if (!Mod) 26 Err.print("DebugInfoTest", errs()); 27 return Mod; 28 } 29 30 namespace { 31 32 TEST(DINodeTest, getFlag) { 33 // Some valid flags. 34 EXPECT_EQ(DINode::FlagPublic, DINode::getFlag("DIFlagPublic")); 35 EXPECT_EQ(DINode::FlagProtected, DINode::getFlag("DIFlagProtected")); 36 EXPECT_EQ(DINode::FlagPrivate, DINode::getFlag("DIFlagPrivate")); 37 EXPECT_EQ(DINode::FlagVector, DINode::getFlag("DIFlagVector")); 38 EXPECT_EQ(DINode::FlagRValueReference, 39 DINode::getFlag("DIFlagRValueReference")); 40 41 // FlagAccessibility shouldn't work. 42 EXPECT_EQ(0u, DINode::getFlag("DIFlagAccessibility")); 43 44 // Some other invalid strings. 45 EXPECT_EQ(0u, DINode::getFlag("FlagVector")); 46 EXPECT_EQ(0u, DINode::getFlag("Vector")); 47 EXPECT_EQ(0u, DINode::getFlag("other things")); 48 EXPECT_EQ(0u, DINode::getFlag("DIFlagOther")); 49 } 50 51 TEST(DINodeTest, getFlagString) { 52 // Some valid flags. 53 EXPECT_EQ(StringRef("DIFlagPublic"), 54 DINode::getFlagString(DINode::FlagPublic)); 55 EXPECT_EQ(StringRef("DIFlagProtected"), 56 DINode::getFlagString(DINode::FlagProtected)); 57 EXPECT_EQ(StringRef("DIFlagPrivate"), 58 DINode::getFlagString(DINode::FlagPrivate)); 59 EXPECT_EQ(StringRef("DIFlagVector"), 60 DINode::getFlagString(DINode::FlagVector)); 61 EXPECT_EQ(StringRef("DIFlagRValueReference"), 62 DINode::getFlagString(DINode::FlagRValueReference)); 63 64 // FlagAccessibility actually equals FlagPublic. 65 EXPECT_EQ(StringRef("DIFlagPublic"), 66 DINode::getFlagString(DINode::FlagAccessibility)); 67 68 // Some other invalid flags. 69 EXPECT_EQ(StringRef(), 70 DINode::getFlagString(DINode::FlagPublic | DINode::FlagVector)); 71 EXPECT_EQ(StringRef(), DINode::getFlagString(DINode::FlagFwdDecl | 72 DINode::FlagArtificial)); 73 EXPECT_EQ(StringRef(), 74 DINode::getFlagString(static_cast<DINode::DIFlags>(0xffff))); 75 } 76 77 TEST(DINodeTest, splitFlags) { 78 // Some valid flags. 79 #define CHECK_SPLIT(FLAGS, VECTOR, REMAINDER) \ 80 { \ 81 SmallVector<DINode::DIFlags, 8> V; \ 82 EXPECT_EQ(REMAINDER, DINode::splitFlags(FLAGS, V)); \ 83 EXPECT_TRUE(makeArrayRef(V).equals(VECTOR)); \ 84 } 85 CHECK_SPLIT(DINode::FlagPublic, {DINode::FlagPublic}, DINode::FlagZero); 86 CHECK_SPLIT(DINode::FlagProtected, {DINode::FlagProtected}, DINode::FlagZero); 87 CHECK_SPLIT(DINode::FlagPrivate, {DINode::FlagPrivate}, DINode::FlagZero); 88 CHECK_SPLIT(DINode::FlagVector, {DINode::FlagVector}, DINode::FlagZero); 89 CHECK_SPLIT(DINode::FlagRValueReference, {DINode::FlagRValueReference}, 90 DINode::FlagZero); 91 DINode::DIFlags Flags[] = {DINode::FlagFwdDecl, DINode::FlagVector}; 92 CHECK_SPLIT(DINode::FlagFwdDecl | DINode::FlagVector, Flags, 93 DINode::FlagZero); 94 CHECK_SPLIT(DINode::FlagZero, {}, DINode::FlagZero); 95 #undef CHECK_SPLIT 96 } 97 98 TEST(StripTest, LoopMetadata) { 99 LLVMContext C; 100 std::unique_ptr<Module> M = parseIR(C, R"( 101 define void @f() !dbg !5 { 102 ret void, !dbg !10, !llvm.loop !11 103 } 104 105 !llvm.dbg.cu = !{!0} 106 !llvm.debugify = !{!3, !3} 107 !llvm.module.flags = !{!4} 108 109 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) 110 !1 = !DIFile(filename: "loop.ll", directory: "/") 111 !2 = !{} 112 !3 = !{i32 1} 113 !4 = !{i32 2, !"Debug Info Version", i32 3} 114 !5 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !7) 115 !6 = !DISubroutineType(types: !2) 116 !7 = !{!8} 117 !8 = !DILocalVariable(name: "1", scope: !5, file: !1, line: 1, type: !9) 118 !9 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned) 119 !10 = !DILocation(line: 1, column: 1, scope: !5) 120 !11 = distinct !{!11, !10, !10} 121 )"); 122 123 // Look up the debug info emission kind for the CU via the loop metadata 124 // attached to the terminator. If, when stripping non-line table debug info, 125 // we update the terminator's metadata correctly, we should be able to 126 // observe the change in emission kind for the CU. 127 auto getEmissionKind = [&]() { 128 Instruction &I = *M->getFunction("f")->getEntryBlock().getFirstNonPHI(); 129 MDNode *LoopMD = I.getMetadata(LLVMContext::MD_loop); 130 return cast<DILocation>(LoopMD->getOperand(1)) 131 ->getScope() 132 ->getSubprogram() 133 ->getUnit() 134 ->getEmissionKind(); 135 }; 136 137 EXPECT_EQ(getEmissionKind(), DICompileUnit::FullDebug); 138 139 bool Changed = stripNonLineTableDebugInfo(*M); 140 EXPECT_TRUE(Changed); 141 142 EXPECT_EQ(getEmissionKind(), DICompileUnit::LineTablesOnly); 143 144 bool BrokenDebugInfo = false; 145 bool HardError = verifyModule(*M, &errs(), &BrokenDebugInfo); 146 EXPECT_FALSE(HardError); 147 EXPECT_FALSE(BrokenDebugInfo); 148 } 149 150 TEST(MetadataTest, DeleteInstUsedByDbgValue) { 151 LLVMContext C; 152 std::unique_ptr<Module> M = parseIR(C, R"( 153 define i16 @f(i16 %a) !dbg !6 { 154 %b = add i16 %a, 1, !dbg !11 155 call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11 156 ret i16 0, !dbg !11 157 } 158 declare void @llvm.dbg.value(metadata, metadata, metadata) #0 159 attributes #0 = { nounwind readnone speculatable willreturn } 160 161 !llvm.dbg.cu = !{!0} 162 !llvm.module.flags = !{!5} 163 164 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) 165 !1 = !DIFile(filename: "t.ll", directory: "/") 166 !2 = !{} 167 !5 = !{i32 2, !"Debug Info Version", i32 3} 168 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) 169 !7 = !DISubroutineType(types: !2) 170 !8 = !{!9} 171 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) 172 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned) 173 !11 = !DILocation(line: 1, column: 1, scope: !6) 174 )"); 175 176 // Find %b = add ... 177 Instruction &I = *M->getFunction("f")->getEntryBlock().getFirstNonPHI(); 178 179 // Find the dbg.value using %b. 180 SmallVector<DbgValueInst *, 1> DVIs; 181 findDbgValues(DVIs, &I); 182 183 // Delete %b. The dbg.value should now point to undef. 184 I.eraseFromParent(); 185 EXPECT_TRUE(isa<UndefValue>(DVIs[0]->getValue())); 186 } 187 188 } // end namespace 189