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
parseIR(LLVMContext & C,const char * IR)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
TEST(DINodeTest,getFlag)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
TEST(DINodeTest,getFlagString)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
TEST(DINodeTest,splitFlags)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
TEST(StripTest,LoopMetadata)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
TEST(MetadataTest,DeleteInstUsedByDbgValue)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