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