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/IR/DIBuilder.h" 11 #include "llvm/AsmParser/Parser.h" 12 #include "llvm/IR/DebugInfoMetadata.h" 13 #include "llvm/IR/IntrinsicInst.h" 14 #include "llvm/IR/LLVMContext.h" 15 #include "llvm/IR/Module.h" 16 #include "llvm/IR/Verifier.h" 17 #include "llvm/Support/SourceMgr.h" 18 #include "llvm/Transforms/Utils/Local.h" 19 #include "gtest/gtest.h" 20 21 using namespace llvm; 22 23 static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { 24 SMDiagnostic Err; 25 std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C); 26 if (!Mod) 27 Err.print("DebugInfoTest", errs()); 28 return Mod; 29 } 30 31 namespace { 32 33 TEST(DINodeTest, getFlag) { 34 // Some valid flags. 35 EXPECT_EQ(DINode::FlagPublic, DINode::getFlag("DIFlagPublic")); 36 EXPECT_EQ(DINode::FlagProtected, DINode::getFlag("DIFlagProtected")); 37 EXPECT_EQ(DINode::FlagPrivate, DINode::getFlag("DIFlagPrivate")); 38 EXPECT_EQ(DINode::FlagVector, DINode::getFlag("DIFlagVector")); 39 EXPECT_EQ(DINode::FlagRValueReference, 40 DINode::getFlag("DIFlagRValueReference")); 41 42 // FlagAccessibility shouldn't work. 43 EXPECT_EQ(0u, DINode::getFlag("DIFlagAccessibility")); 44 45 // Some other invalid strings. 46 EXPECT_EQ(0u, DINode::getFlag("FlagVector")); 47 EXPECT_EQ(0u, DINode::getFlag("Vector")); 48 EXPECT_EQ(0u, DINode::getFlag("other things")); 49 EXPECT_EQ(0u, DINode::getFlag("DIFlagOther")); 50 } 51 52 TEST(DINodeTest, getFlagString) { 53 // Some valid flags. 54 EXPECT_EQ(StringRef("DIFlagPublic"), 55 DINode::getFlagString(DINode::FlagPublic)); 56 EXPECT_EQ(StringRef("DIFlagProtected"), 57 DINode::getFlagString(DINode::FlagProtected)); 58 EXPECT_EQ(StringRef("DIFlagPrivate"), 59 DINode::getFlagString(DINode::FlagPrivate)); 60 EXPECT_EQ(StringRef("DIFlagVector"), 61 DINode::getFlagString(DINode::FlagVector)); 62 EXPECT_EQ(StringRef("DIFlagRValueReference"), 63 DINode::getFlagString(DINode::FlagRValueReference)); 64 65 // FlagAccessibility actually equals FlagPublic. 66 EXPECT_EQ(StringRef("DIFlagPublic"), 67 DINode::getFlagString(DINode::FlagAccessibility)); 68 69 // Some other invalid flags. 70 EXPECT_EQ(StringRef(), 71 DINode::getFlagString(DINode::FlagPublic | DINode::FlagVector)); 72 EXPECT_EQ(StringRef(), DINode::getFlagString(DINode::FlagFwdDecl | 73 DINode::FlagArtificial)); 74 EXPECT_EQ(StringRef(), 75 DINode::getFlagString(static_cast<DINode::DIFlags>(0xffff))); 76 } 77 78 TEST(DINodeTest, splitFlags) { 79 // Some valid flags. 80 #define CHECK_SPLIT(FLAGS, VECTOR, REMAINDER) \ 81 { \ 82 SmallVector<DINode::DIFlags, 8> V; \ 83 EXPECT_EQ(REMAINDER, DINode::splitFlags(FLAGS, V)); \ 84 EXPECT_TRUE(makeArrayRef(V).equals(VECTOR)); \ 85 } 86 CHECK_SPLIT(DINode::FlagPublic, {DINode::FlagPublic}, DINode::FlagZero); 87 CHECK_SPLIT(DINode::FlagProtected, {DINode::FlagProtected}, DINode::FlagZero); 88 CHECK_SPLIT(DINode::FlagPrivate, {DINode::FlagPrivate}, DINode::FlagZero); 89 CHECK_SPLIT(DINode::FlagVector, {DINode::FlagVector}, DINode::FlagZero); 90 CHECK_SPLIT(DINode::FlagRValueReference, {DINode::FlagRValueReference}, 91 DINode::FlagZero); 92 DINode::DIFlags Flags[] = {DINode::FlagFwdDecl, DINode::FlagVector}; 93 CHECK_SPLIT(DINode::FlagFwdDecl | DINode::FlagVector, Flags, 94 DINode::FlagZero); 95 CHECK_SPLIT(DINode::FlagZero, {}, DINode::FlagZero); 96 #undef CHECK_SPLIT 97 } 98 99 TEST(StripTest, LoopMetadata) { 100 LLVMContext C; 101 std::unique_ptr<Module> M = parseIR(C, R"( 102 define void @f() !dbg !5 { 103 ret void, !dbg !10, !llvm.loop !11 104 } 105 106 !llvm.dbg.cu = !{!0} 107 !llvm.debugify = !{!3, !3} 108 !llvm.module.flags = !{!4} 109 110 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) 111 !1 = !DIFile(filename: "loop.ll", directory: "/") 112 !2 = !{} 113 !3 = !{i32 1} 114 !4 = !{i32 2, !"Debug Info Version", i32 3} 115 !5 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !7) 116 !6 = !DISubroutineType(types: !2) 117 !7 = !{!8} 118 !8 = !DILocalVariable(name: "1", scope: !5, file: !1, line: 1, type: !9) 119 !9 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned) 120 !10 = !DILocation(line: 1, column: 1, scope: !5) 121 !11 = distinct !{!11, !10, !10} 122 )"); 123 124 // Look up the debug info emission kind for the CU via the loop metadata 125 // attached to the terminator. If, when stripping non-line table debug info, 126 // we update the terminator's metadata correctly, we should be able to 127 // observe the change in emission kind for the CU. 128 auto getEmissionKind = [&]() { 129 Instruction &I = *M->getFunction("f")->getEntryBlock().getFirstNonPHI(); 130 MDNode *LoopMD = I.getMetadata(LLVMContext::MD_loop); 131 return cast<DILocation>(LoopMD->getOperand(1)) 132 ->getScope() 133 ->getSubprogram() 134 ->getUnit() 135 ->getEmissionKind(); 136 }; 137 138 EXPECT_EQ(getEmissionKind(), DICompileUnit::FullDebug); 139 140 bool Changed = stripNonLineTableDebugInfo(*M); 141 EXPECT_TRUE(Changed); 142 143 EXPECT_EQ(getEmissionKind(), DICompileUnit::LineTablesOnly); 144 145 bool BrokenDebugInfo = false; 146 bool HardError = verifyModule(*M, &errs(), &BrokenDebugInfo); 147 EXPECT_FALSE(HardError); 148 EXPECT_FALSE(BrokenDebugInfo); 149 } 150 151 TEST(MetadataTest, DeleteInstUsedByDbgValue) { 152 LLVMContext C; 153 std::unique_ptr<Module> M = parseIR(C, R"( 154 define i16 @f(i16 %a) !dbg !6 { 155 %b = add i16 %a, 1, !dbg !11 156 call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11 157 ret i16 0, !dbg !11 158 } 159 declare void @llvm.dbg.value(metadata, metadata, metadata) #0 160 attributes #0 = { nounwind readnone speculatable willreturn } 161 162 !llvm.dbg.cu = !{!0} 163 !llvm.module.flags = !{!5} 164 165 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) 166 !1 = !DIFile(filename: "t.ll", directory: "/") 167 !2 = !{} 168 !5 = !{i32 2, !"Debug Info Version", i32 3} 169 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) 170 !7 = !DISubroutineType(types: !2) 171 !8 = !{!9} 172 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) 173 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned) 174 !11 = !DILocation(line: 1, column: 1, scope: !6) 175 )"); 176 177 // Find %b = add ... 178 Instruction &I = *M->getFunction("f")->getEntryBlock().getFirstNonPHI(); 179 180 // Find the dbg.value using %b. 181 SmallVector<DbgValueInst *, 1> DVIs; 182 findDbgValues(DVIs, &I); 183 184 // Delete %b. The dbg.value should now point to undef. 185 I.eraseFromParent(); 186 EXPECT_TRUE(isa<UndefValue>(DVIs[0]->getValue())); 187 } 188 189 TEST(DIBuilder, CreateFortranArrayTypeWithAttributes) { 190 LLVMContext Ctx; 191 std::unique_ptr<Module> M(new Module("MyModule", Ctx)); 192 DIBuilder DIB(*M); 193 194 DISubrange *Subrange = DIB.getOrCreateSubrange(1,1); 195 SmallVector<Metadata*, 4> Subranges; 196 Subranges.push_back(Subrange); 197 DINodeArray Subscripts = DIB.getOrCreateArray(Subranges); 198 199 auto getDIExpression = [&DIB](int offset) { 200 SmallVector<uint64_t, 4> ops; 201 ops.push_back(llvm::dwarf::DW_OP_push_object_address); 202 DIExpression::appendOffset(ops, offset); 203 ops.push_back(llvm::dwarf::DW_OP_deref); 204 205 return DIB.createExpression(ops); 206 }; 207 208 DIFile *F = DIB.createFile("main.c", "/"); 209 DICompileUnit *CU = DIB.createCompileUnit( 210 dwarf::DW_LANG_C, DIB.createFile("main.c", "/"), "llvm-c", true, "", 0); 211 212 DIVariable *DataLocation = 213 DIB.createTempGlobalVariableFwdDecl(CU, "dl", "_dl", F, 1, nullptr, true); 214 DIExpression *Associated = getDIExpression(1); 215 DIExpression *Allocated = getDIExpression(2); 216 DIExpression *Rank = DIB.createConstantValueExpression(3); 217 218 DICompositeType *ArrayType = DIB.createArrayType(0, 0, nullptr, Subscripts, 219 DataLocation, Associated, 220 Allocated, Rank); 221 222 EXPECT_TRUE(isa_and_nonnull<DICompositeType>(ArrayType)); 223 EXPECT_EQ(ArrayType->getRawDataLocation(), DataLocation); 224 EXPECT_EQ(ArrayType->getRawAssociated(), Associated); 225 EXPECT_EQ(ArrayType->getRawAllocated(), Allocated); 226 EXPECT_EQ(ArrayType->getRawRank(), Rank); 227 228 // Avoid memory leak. 229 DIVariable::deleteTemporary(DataLocation); 230 } 231 232 } // end namespace 233