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/LLVMContext.h" 13 #include "llvm/IR/Module.h" 14 #include "llvm/IR/Verifier.h" 15 #include "llvm/Support/SourceMgr.h" 16 #include "gtest/gtest.h" 17 18 using namespace llvm; 19 20 static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { 21 SMDiagnostic Err; 22 std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C); 23 if (!Mod) 24 Err.print("DebugInfoTest", errs()); 25 return Mod; 26 } 27 28 namespace { 29 30 TEST(DINodeTest, getFlag) { 31 // Some valid flags. 32 EXPECT_EQ(DINode::FlagPublic, DINode::getFlag("DIFlagPublic")); 33 EXPECT_EQ(DINode::FlagProtected, DINode::getFlag("DIFlagProtected")); 34 EXPECT_EQ(DINode::FlagPrivate, DINode::getFlag("DIFlagPrivate")); 35 EXPECT_EQ(DINode::FlagVector, DINode::getFlag("DIFlagVector")); 36 EXPECT_EQ(DINode::FlagRValueReference, 37 DINode::getFlag("DIFlagRValueReference")); 38 39 // FlagAccessibility shouldn't work. 40 EXPECT_EQ(0u, DINode::getFlag("DIFlagAccessibility")); 41 42 // Some other invalid strings. 43 EXPECT_EQ(0u, DINode::getFlag("FlagVector")); 44 EXPECT_EQ(0u, DINode::getFlag("Vector")); 45 EXPECT_EQ(0u, DINode::getFlag("other things")); 46 EXPECT_EQ(0u, DINode::getFlag("DIFlagOther")); 47 } 48 49 TEST(DINodeTest, getFlagString) { 50 // Some valid flags. 51 EXPECT_EQ(StringRef("DIFlagPublic"), 52 DINode::getFlagString(DINode::FlagPublic)); 53 EXPECT_EQ(StringRef("DIFlagProtected"), 54 DINode::getFlagString(DINode::FlagProtected)); 55 EXPECT_EQ(StringRef("DIFlagPrivate"), 56 DINode::getFlagString(DINode::FlagPrivate)); 57 EXPECT_EQ(StringRef("DIFlagVector"), 58 DINode::getFlagString(DINode::FlagVector)); 59 EXPECT_EQ(StringRef("DIFlagRValueReference"), 60 DINode::getFlagString(DINode::FlagRValueReference)); 61 62 // FlagAccessibility actually equals FlagPublic. 63 EXPECT_EQ(StringRef("DIFlagPublic"), 64 DINode::getFlagString(DINode::FlagAccessibility)); 65 66 // Some other invalid flags. 67 EXPECT_EQ(StringRef(), 68 DINode::getFlagString(DINode::FlagPublic | DINode::FlagVector)); 69 EXPECT_EQ(StringRef(), DINode::getFlagString(DINode::FlagFwdDecl | 70 DINode::FlagArtificial)); 71 EXPECT_EQ(StringRef(), 72 DINode::getFlagString(static_cast<DINode::DIFlags>(0xffff))); 73 } 74 75 TEST(DINodeTest, splitFlags) { 76 // Some valid flags. 77 #define CHECK_SPLIT(FLAGS, VECTOR, REMAINDER) \ 78 { \ 79 SmallVector<DINode::DIFlags, 8> V; \ 80 EXPECT_EQ(REMAINDER, DINode::splitFlags(FLAGS, V)); \ 81 EXPECT_TRUE(makeArrayRef(V).equals(VECTOR)); \ 82 } 83 CHECK_SPLIT(DINode::FlagPublic, {DINode::FlagPublic}, DINode::FlagZero); 84 CHECK_SPLIT(DINode::FlagProtected, {DINode::FlagProtected}, DINode::FlagZero); 85 CHECK_SPLIT(DINode::FlagPrivate, {DINode::FlagPrivate}, DINode::FlagZero); 86 CHECK_SPLIT(DINode::FlagVector, {DINode::FlagVector}, DINode::FlagZero); 87 CHECK_SPLIT(DINode::FlagRValueReference, {DINode::FlagRValueReference}, 88 DINode::FlagZero); 89 DINode::DIFlags Flags[] = {DINode::FlagFwdDecl, DINode::FlagVector}; 90 CHECK_SPLIT(DINode::FlagFwdDecl | DINode::FlagVector, Flags, 91 DINode::FlagZero); 92 CHECK_SPLIT(DINode::FlagZero, {}, DINode::FlagZero); 93 #undef CHECK_SPLIT 94 } 95 96 TEST(StripTest, LoopMetadata) { 97 LLVMContext C; 98 std::unique_ptr<Module> M = parseIR(C, R"( 99 define void @f() !dbg !5 { 100 ret void, !dbg !10, !llvm.loop !11 101 } 102 103 !llvm.dbg.cu = !{!0} 104 !llvm.debugify = !{!3, !3} 105 !llvm.module.flags = !{!4} 106 107 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) 108 !1 = !DIFile(filename: "loop.ll", directory: "/") 109 !2 = !{} 110 !3 = !{i32 1} 111 !4 = !{i32 2, !"Debug Info Version", i32 3} 112 !5 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !7) 113 !6 = !DISubroutineType(types: !2) 114 !7 = !{!8} 115 !8 = !DILocalVariable(name: "1", scope: !5, file: !1, line: 1, type: !9) 116 !9 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned) 117 !10 = !DILocation(line: 1, column: 1, scope: !5) 118 !11 = distinct !{!11, !10, !10} 119 )"); 120 121 // Look up the debug info emission kind for the CU via the loop metadata 122 // attached to the terminator. If, when stripping non-line table debug info, 123 // we update the terminator's metadata correctly, we should be able to 124 // observe the change in emission kind for the CU. 125 auto getEmissionKind = [&]() { 126 Instruction &I = *M->getFunction("f")->getEntryBlock().getFirstNonPHI(); 127 MDNode *LoopMD = I.getMetadata(LLVMContext::MD_loop); 128 return cast<DILocation>(LoopMD->getOperand(1)) 129 ->getScope() 130 ->getSubprogram() 131 ->getUnit() 132 ->getEmissionKind(); 133 }; 134 135 EXPECT_EQ(getEmissionKind(), DICompileUnit::FullDebug); 136 137 bool Changed = stripNonLineTableDebugInfo(*M); 138 EXPECT_TRUE(Changed); 139 140 EXPECT_EQ(getEmissionKind(), DICompileUnit::LineTablesOnly); 141 142 bool BrokenDebugInfo = false; 143 bool HardError = verifyModule(*M, &errs(), &BrokenDebugInfo); 144 EXPECT_FALSE(HardError); 145 EXPECT_FALSE(BrokenDebugInfo); 146 } 147 148 } // end namespace 149