1 //===- llvm/unittest/IR/DebugInfo.cpp - DebugInfo tests -------------------===//
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
7 //===----------------------------------------------------------------------===//
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/IRBuilder.h"
15 #include "llvm/IR/IntrinsicInst.h"
16 #include "llvm/IR/LLVMContext.h"
17 #include "llvm/IR/Metadata.h"
18 #include "llvm/IR/Module.h"
19 #include "llvm/IR/Verifier.h"
20 #include "llvm/Support/SourceMgr.h"
21 #include "llvm/Transforms/Utils/Local.h"
22 #include "gtest/gtest.h"
26 static std::unique_ptr
<Module
> parseIR(LLVMContext
&C
, const char *IR
) {
28 std::unique_ptr
<Module
> Mod
= parseAssemblyString(IR
, Err
, C
);
30 Err
.print("DebugInfoTest", errs());
36 TEST(DINodeTest
, getFlag
) {
38 EXPECT_EQ(DINode::FlagPublic
, DINode::getFlag("DIFlagPublic"));
39 EXPECT_EQ(DINode::FlagProtected
, DINode::getFlag("DIFlagProtected"));
40 EXPECT_EQ(DINode::FlagPrivate
, DINode::getFlag("DIFlagPrivate"));
41 EXPECT_EQ(DINode::FlagVector
, DINode::getFlag("DIFlagVector"));
42 EXPECT_EQ(DINode::FlagRValueReference
,
43 DINode::getFlag("DIFlagRValueReference"));
45 // FlagAccessibility shouldn't work.
46 EXPECT_EQ(0u, DINode::getFlag("DIFlagAccessibility"));
48 // Some other invalid strings.
49 EXPECT_EQ(0u, DINode::getFlag("FlagVector"));
50 EXPECT_EQ(0u, DINode::getFlag("Vector"));
51 EXPECT_EQ(0u, DINode::getFlag("other things"));
52 EXPECT_EQ(0u, DINode::getFlag("DIFlagOther"));
55 TEST(DINodeTest
, getFlagString
) {
57 EXPECT_EQ(StringRef("DIFlagPublic"),
58 DINode::getFlagString(DINode::FlagPublic
));
59 EXPECT_EQ(StringRef("DIFlagProtected"),
60 DINode::getFlagString(DINode::FlagProtected
));
61 EXPECT_EQ(StringRef("DIFlagPrivate"),
62 DINode::getFlagString(DINode::FlagPrivate
));
63 EXPECT_EQ(StringRef("DIFlagVector"),
64 DINode::getFlagString(DINode::FlagVector
));
65 EXPECT_EQ(StringRef("DIFlagRValueReference"),
66 DINode::getFlagString(DINode::FlagRValueReference
));
68 // FlagAccessibility actually equals FlagPublic.
69 EXPECT_EQ(StringRef("DIFlagPublic"),
70 DINode::getFlagString(DINode::FlagAccessibility
));
72 // Some other invalid flags.
73 EXPECT_EQ(StringRef(),
74 DINode::getFlagString(DINode::FlagPublic
| DINode::FlagVector
));
75 EXPECT_EQ(StringRef(), DINode::getFlagString(DINode::FlagFwdDecl
|
76 DINode::FlagArtificial
));
77 EXPECT_EQ(StringRef(),
78 DINode::getFlagString(static_cast<DINode::DIFlags
>(0xffff)));
81 TEST(DINodeTest
, splitFlags
) {
83 #define CHECK_SPLIT(FLAGS, VECTOR, REMAINDER) \
85 SmallVector<DINode::DIFlags, 8> V; \
86 EXPECT_EQ(REMAINDER, DINode::splitFlags(FLAGS, V)); \
87 EXPECT_TRUE(makeArrayRef(V).equals(VECTOR)); \
89 CHECK_SPLIT(DINode::FlagPublic
, {DINode::FlagPublic
}, DINode::FlagZero
);
90 CHECK_SPLIT(DINode::FlagProtected
, {DINode::FlagProtected
}, DINode::FlagZero
);
91 CHECK_SPLIT(DINode::FlagPrivate
, {DINode::FlagPrivate
}, DINode::FlagZero
);
92 CHECK_SPLIT(DINode::FlagVector
, {DINode::FlagVector
}, DINode::FlagZero
);
93 CHECK_SPLIT(DINode::FlagRValueReference
, {DINode::FlagRValueReference
},
95 DINode::DIFlags Flags
[] = {DINode::FlagFwdDecl
, DINode::FlagVector
};
96 CHECK_SPLIT(DINode::FlagFwdDecl
| DINode::FlagVector
, Flags
,
98 CHECK_SPLIT(DINode::FlagZero
, {}, DINode::FlagZero
);
102 TEST(StripTest
, LoopMetadata
) {
104 std::unique_ptr
<Module
> M
= parseIR(C
, R
"(
105 define void @f() !dbg !5 {
106 ret void, !dbg !10, !llvm.loop !11
110 !llvm.debugify = !{!3, !3}
111 !llvm.module.flags = !{!4}
113 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify
", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
114 !1 = !DIFile(filename: "loop
.ll
", directory: "/")
117 !4 = !{i32 2, !"Debug Info Version
", i32 3}
118 !5 = distinct !DISubprogram(name: "f
", linkageName: "f
", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !7)
119 !6 = !DISubroutineType(types: !2)
121 !8 = !DILocalVariable(name: "1", scope: !5, file: !1, line: 1, type: !9)
122 !9 = !DIBasicType(name: "ty32
", size: 32, encoding: DW_ATE_unsigned)
123 !10 = !DILocation(line: 1, column: 1, scope: !5)
124 !11 = distinct !{!11, !10, !10}
127 // Look up the debug info emission kind for the CU via the loop metadata
128 // attached to the terminator. If, when stripping non-line table debug info,
129 // we update the terminator's metadata correctly, we should be able to
130 // observe the change in emission kind for the CU.
131 auto getEmissionKind
= [&]() {
132 Instruction
&I
= *M
->getFunction("f")->getEntryBlock().getFirstNonPHI();
133 MDNode
*LoopMD
= I
.getMetadata(LLVMContext::MD_loop
);
134 return cast
<DILocation
>(LoopMD
->getOperand(1))
141 EXPECT_EQ(getEmissionKind(), DICompileUnit::FullDebug
);
143 bool Changed
= stripNonLineTableDebugInfo(*M
);
144 EXPECT_TRUE(Changed
);
146 EXPECT_EQ(getEmissionKind(), DICompileUnit::LineTablesOnly
);
148 bool BrokenDebugInfo
= false;
149 bool HardError
= verifyModule(*M
, &errs(), &BrokenDebugInfo
);
150 EXPECT_FALSE(HardError
);
151 EXPECT_FALSE(BrokenDebugInfo
);
154 TEST(MetadataTest
, DeleteInstUsedByDbgValue
) {
156 std::unique_ptr
<Module
> M
= parseIR(C
, R
"(
157 define i16 @f(i16 %a) !dbg !6 {
158 %b = add i16 %a, 1, !dbg !11
159 call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
162 declare void @llvm.dbg.value(metadata, metadata, metadata) #0
163 attributes #0 = { nounwind readnone speculatable willreturn }
166 !llvm.module.flags = !{!5}
168 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify
", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
169 !1 = !DIFile(filename: "t
.ll
", directory: "/")
171 !5 = !{i32 2, !"Debug Info Version
", i32 3}
172 !6 = distinct !DISubprogram(name: "foo
", linkageName: "foo
", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
173 !7 = !DISubroutineType(types: !2)
175 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
176 !10 = !DIBasicType(name: "ty16
", size: 16, encoding: DW_ATE_unsigned)
177 !11 = !DILocation(line: 1, column: 1, scope: !6)
181 Instruction
&I
= *M
->getFunction("f")->getEntryBlock().getFirstNonPHI();
183 // Find the dbg.value using %b.
184 SmallVector
<DbgValueInst
*, 1> DVIs
;
185 findDbgValues(DVIs
, &I
);
187 // Delete %b. The dbg.value should now point to undef.
189 EXPECT_EQ(DVIs
[0]->getNumVariableLocationOps(), 1u);
190 EXPECT_TRUE(isa
<UndefValue
>(DVIs
[0]->getValue(0)));
193 TEST(DIBuilder
, CreateFortranArrayTypeWithAttributes
) {
195 std::unique_ptr
<Module
> M(new Module("MyModule", Ctx
));
198 DISubrange
*Subrange
= DIB
.getOrCreateSubrange(1,1);
199 SmallVector
<Metadata
*, 4> Subranges
;
200 Subranges
.push_back(Subrange
);
201 DINodeArray Subscripts
= DIB
.getOrCreateArray(Subranges
);
203 auto getDIExpression
= [&DIB
](int offset
) {
204 SmallVector
<uint64_t, 4> ops
;
205 ops
.push_back(llvm::dwarf::DW_OP_push_object_address
);
206 DIExpression::appendOffset(ops
, offset
);
207 ops
.push_back(llvm::dwarf::DW_OP_deref
);
209 return DIB
.createExpression(ops
);
212 DIFile
*F
= DIB
.createFile("main.c", "/");
213 DICompileUnit
*CU
= DIB
.createCompileUnit(
214 dwarf::DW_LANG_C
, DIB
.createFile("main.c", "/"), "llvm-c", true, "", 0);
216 DIVariable
*DataLocation
=
217 DIB
.createTempGlobalVariableFwdDecl(CU
, "dl", "_dl", F
, 1, nullptr, true);
218 DIExpression
*Associated
= getDIExpression(1);
219 DIExpression
*Allocated
= getDIExpression(2);
220 DIExpression
*Rank
= DIB
.createConstantValueExpression(3);
222 DICompositeType
*ArrayType
= DIB
.createArrayType(0, 0, nullptr, Subscripts
,
223 DataLocation
, Associated
,
226 EXPECT_TRUE(isa_and_nonnull
<DICompositeType
>(ArrayType
));
227 EXPECT_EQ(ArrayType
->getRawDataLocation(), DataLocation
);
228 EXPECT_EQ(ArrayType
->getRawAssociated(), Associated
);
229 EXPECT_EQ(ArrayType
->getRawAllocated(), Allocated
);
230 EXPECT_EQ(ArrayType
->getRawRank(), Rank
);
232 // Avoid memory leak.
233 DIVariable::deleteTemporary(DataLocation
);
236 TEST(DIBuilder
, CreateSetType
) {
238 std::unique_ptr
<Module
> M(new Module("MyModule", Ctx
));
240 DIScope
*Scope
= DISubprogram::getDistinct(
241 Ctx
, nullptr, "", "", nullptr, 0, nullptr, 0, nullptr, 0, 0,
242 DINode::FlagZero
, DISubprogram::SPFlagZero
, nullptr);
243 DIType
*Type
= DIB
.createBasicType("Int", 64, dwarf::DW_ATE_signed
);
244 DIFile
*F
= DIB
.createFile("main.c", "/");
246 DIDerivedType
*SetType
= DIB
.createSetType(Scope
, "set1", F
, 1, 64, 64, Type
);
247 EXPECT_TRUE(isa_and_nonnull
<DIDerivedType
>(SetType
));
250 TEST(DIBuilder
, CreateStringType
) {
252 std::unique_ptr
<Module
> M(new Module("MyModule", Ctx
));
254 DIScope
*Scope
= DISubprogram::getDistinct(
255 Ctx
, nullptr, "", "", nullptr, 0, nullptr, 0, nullptr, 0, 0,
256 DINode::FlagZero
, DISubprogram::SPFlagZero
, nullptr);
257 DIFile
*F
= DIB
.createFile("main.c", "/");
258 StringRef StrName
= "string";
259 DIVariable
*StringLen
= DIB
.createAutoVariable(Scope
, StrName
, F
, 0, nullptr,
260 false, DINode::FlagZero
, 0);
261 auto getDIExpression
= [&DIB
](int offset
) {
262 SmallVector
<uint64_t, 4> ops
;
263 ops
.push_back(llvm::dwarf::DW_OP_push_object_address
);
264 DIExpression::appendOffset(ops
, offset
);
265 ops
.push_back(llvm::dwarf::DW_OP_deref
);
267 return DIB
.createExpression(ops
);
269 DIExpression
*StringLocationExp
= getDIExpression(1);
270 DIStringType
*StringType
=
271 DIB
.createStringType(StrName
, StringLen
, StringLocationExp
);
273 EXPECT_TRUE(isa_and_nonnull
<DIStringType
>(StringType
));
274 EXPECT_EQ(StringType
->getName(), StrName
);
275 EXPECT_EQ(StringType
->getStringLength(), StringLen
);
276 EXPECT_EQ(StringType
->getStringLocationExp(), StringLocationExp
);
278 StringRef StrNameExp
= "stringexp";
279 DIExpression
*StringLengthExp
= getDIExpression(2);
280 DIStringType
*StringTypeExp
=
281 DIB
.createStringType(StrNameExp
, StringLengthExp
, StringLocationExp
);
283 EXPECT_TRUE(isa_and_nonnull
<DIStringType
>(StringTypeExp
));
284 EXPECT_EQ(StringTypeExp
->getName(), StrNameExp
);
285 EXPECT_EQ(StringTypeExp
->getStringLocationExp(), StringLocationExp
);
286 EXPECT_EQ(StringTypeExp
->getStringLengthExp(), StringLengthExp
);
289 TEST(DIBuilder
, DIEnumerator
) {
291 std::unique_ptr
<Module
> M(new Module("MyModule", Ctx
));
293 APSInt
I1(APInt(32, 1));
294 APSInt
I2(APInt(33, 1));
296 auto *E
= DIEnumerator::get(Ctx
, I1
, I1
.isSigned(), "name");
299 auto *E1
= DIEnumerator::getIfExists(Ctx
, I1
, I1
.isSigned(), "name");
302 auto *E2
= DIEnumerator::getIfExists(Ctx
, I2
, I1
.isSigned(), "name");
306 TEST(DIBuilder
, createDbgAddr
) {
308 std::unique_ptr
<Module
> M
= parseIR(C
, R
"(
309 define void @f() !dbg !6 {
310 %a = alloca i16, align 8
311 ;; It is important that we put the debug marker on the return.
312 ;; We take advantage of that to conjure up a debug loc without
313 ;; having to synthesize one programatically.
316 declare void @llvm.dbg.value(metadata, metadata, metadata) #0
317 attributes #0 = { nounwind readnone speculatable willreturn }
320 !llvm.module.flags = !{!5}
322 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify
", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
323 !1 = !DIFile(filename: "t
.ll
", directory: "/")
325 !5 = !{i32 2, !"Debug Info Version
", i32 3}
326 !6 = distinct !DISubprogram(name: "foo
", linkageName: "foo
", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
327 !7 = !DISubroutineType(types: !2)
329 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
330 !10 = !DIBasicType(name: "ty16
", size: 16, encoding: DW_ATE_unsigned)
331 !11 = !DILocation(line: 1, column: 1, scope: !6)
333 auto *F
= M
->getFunction("f");
334 auto *EntryBlock
= &F
->getEntryBlock();
337 cast
<DICompileUnit
>(M
->getNamedMetadata("llvm.dbg.cu")->getOperand(0));
338 auto *Alloca
= &*EntryBlock
->begin();
339 auto *Ret
= EntryBlock
->getTerminator();
341 auto *SP
= cast
<DISubprogram
>(F
->getMetadata(LLVMContext::MD_dbg
));
342 auto *File
= SP
->getFile();
343 std::string Name
= "myName";
344 const auto *Loc
= Ret
->getDebugLoc().get();
346 IRBuilder
<> Builder(EntryBlock
);
347 DIBuilder
DIB(*M
, true, CU
);
348 DIType
*DT
= DIB
.createBasicType("ty16", 16, dwarf::DW_ATE_unsigned
);
350 DILocalVariable
*LocalVar
=
351 DIB
.createAutoVariable(SP
, Name
, File
, 5 /*line*/, DT
,
352 /*AlwaysPreserve=*/true);
354 auto *Inst
= DIB
.insertDbgAddrIntrinsic(Alloca
, LocalVar
,
355 DIB
.createExpression(), Loc
, Ret
);
359 EXPECT_EQ(Inst
->getDebugLoc().get(), Loc
);
361 auto *MD0
= cast
<MetadataAsValue
>(Inst
->getOperand(0))->getMetadata();
362 auto *MD0Local
= cast
<LocalAsMetadata
>(MD0
);
363 EXPECT_EQ(MD0Local
->getValue(), Alloca
);
364 auto *MD1
= cast
<MetadataAsValue
>(Inst
->getOperand(1))->getMetadata();
365 EXPECT_EQ(MD1
->getMetadataID(), Metadata::MetadataKind::DILocalVariableKind
);
366 auto *MD2
= cast
<MetadataAsValue
>(Inst
->getOperand(2))->getMetadata();
367 auto *MDExp
= cast
<DIExpression
>(MD2
);
368 EXPECT_EQ(MDExp
->getNumElements(), 0u);