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