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(ArrayRef(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(DbgVariableIntrinsic
, EmptyMDIsKillLocation
) {
195 std::unique_ptr
<Module
> M
= parseIR(Ctx
, R
"(
196 define dso_local void @fun() local_unnamed_addr #0 !dbg !9 {
198 call void @llvm.dbg.declare(metadata !{}, metadata !13, metadata !DIExpression()), !dbg !16
202 declare void @llvm.dbg.declare(metadata, metadata, metadata)
205 !llvm.module.flags = !{!2, !3}
208 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version
16.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
209 !1 = !DIFile(filename: "test
.c
", directory: "/")
210 !2 = !{i32 7, !"Dwarf Version
", i32 5}
211 !3 = !{i32 2, !"Debug Info Version
", i32 3}
212 !8 = !{!"clang version
16.0.0"}
213 !9 = distinct !DISubprogram(name: "fun
", scope: !1, file: !1, line: 1, type: !10, scopeLine: 1, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12)
214 !10 = !DISubroutineType(types: !11)
217 !13 = !DILocalVariable(name: "a
", scope: !9, file: !1, line: 1, type: !14)
218 !14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
219 !16 = !DILocation(line: 1, column: 21, scope: !9)
222 bool BrokenDebugInfo
= true;
223 verifyModule(*M
, &errs(), &BrokenDebugInfo
);
224 ASSERT_FALSE(BrokenDebugInfo
);
226 // Get the dbg.declare.
227 Function
&F
= *cast
<Function
>(M
->getNamedValue("fun"));
228 DbgVariableIntrinsic
*DbgDeclare
=
229 cast
<DbgVariableIntrinsic
>(&F
.front().front());
230 // Check that this form counts as a "no location" marker.
231 EXPECT_TRUE(DbgDeclare
->isKillLocation());
234 TEST(DIBuiler
, CreateFile
) {
236 std::unique_ptr
<Module
> M(new Module("MyModule", Ctx
));
239 DIFile
*F
= DIB
.createFile("main.c", "/");
240 EXPECT_EQ(std::nullopt
, F
->getSource());
242 std::optional
<DIFile::ChecksumInfo
<StringRef
>> Checksum
;
243 std::optional
<StringRef
> Source
;
244 F
= DIB
.createFile("main.c", "/", Checksum
, Source
);
245 EXPECT_EQ(Source
, F
->getSource());
248 F
= DIB
.createFile("main.c", "/", Checksum
, Source
);
249 EXPECT_EQ(Source
, F
->getSource());
252 TEST(DIBuilder
, CreateFortranArrayTypeWithAttributes
) {
254 std::unique_ptr
<Module
> M(new Module("MyModule", Ctx
));
257 DISubrange
*Subrange
= DIB
.getOrCreateSubrange(1,1);
258 SmallVector
<Metadata
*, 4> Subranges
;
259 Subranges
.push_back(Subrange
);
260 DINodeArray Subscripts
= DIB
.getOrCreateArray(Subranges
);
262 auto getDIExpression
= [&DIB
](int offset
) {
263 SmallVector
<uint64_t, 4> ops
;
264 ops
.push_back(llvm::dwarf::DW_OP_push_object_address
);
265 DIExpression::appendOffset(ops
, offset
);
266 ops
.push_back(llvm::dwarf::DW_OP_deref
);
268 return DIB
.createExpression(ops
);
271 DIFile
*F
= DIB
.createFile("main.c", "/");
272 DICompileUnit
*CU
= DIB
.createCompileUnit(
273 dwarf::DW_LANG_C
, DIB
.createFile("main.c", "/"), "llvm-c", true, "", 0);
275 DIVariable
*DataLocation
=
276 DIB
.createTempGlobalVariableFwdDecl(CU
, "dl", "_dl", F
, 1, nullptr, true);
277 DIExpression
*Associated
= getDIExpression(1);
278 DIExpression
*Allocated
= getDIExpression(2);
279 DIExpression
*Rank
= DIB
.createConstantValueExpression(3);
281 DICompositeType
*ArrayType
= DIB
.createArrayType(0, 0, nullptr, Subscripts
,
282 DataLocation
, Associated
,
285 EXPECT_TRUE(isa_and_nonnull
<DICompositeType
>(ArrayType
));
286 EXPECT_EQ(ArrayType
->getRawDataLocation(), DataLocation
);
287 EXPECT_EQ(ArrayType
->getRawAssociated(), Associated
);
288 EXPECT_EQ(ArrayType
->getRawAllocated(), Allocated
);
289 EXPECT_EQ(ArrayType
->getRawRank(), Rank
);
291 // Avoid memory leak.
292 DIVariable::deleteTemporary(DataLocation
);
295 TEST(DIBuilder
, CreateSetType
) {
297 std::unique_ptr
<Module
> M(new Module("MyModule", Ctx
));
299 DIScope
*Scope
= DISubprogram::getDistinct(
300 Ctx
, nullptr, "", "", nullptr, 0, nullptr, 0, nullptr, 0, 0,
301 DINode::FlagZero
, DISubprogram::SPFlagZero
, nullptr);
302 DIType
*Type
= DIB
.createBasicType("Int", 64, dwarf::DW_ATE_signed
);
303 DIFile
*F
= DIB
.createFile("main.c", "/");
305 DIDerivedType
*SetType
= DIB
.createSetType(Scope
, "set1", F
, 1, 64, 64, Type
);
306 EXPECT_TRUE(isa_and_nonnull
<DIDerivedType
>(SetType
));
309 TEST(DIBuilder
, CreateStringType
) {
311 std::unique_ptr
<Module
> M(new Module("MyModule", Ctx
));
313 DIScope
*Scope
= DISubprogram::getDistinct(
314 Ctx
, nullptr, "", "", nullptr, 0, nullptr, 0, nullptr, 0, 0,
315 DINode::FlagZero
, DISubprogram::SPFlagZero
, nullptr);
316 DIFile
*F
= DIB
.createFile("main.c", "/");
317 StringRef StrName
= "string";
318 DIVariable
*StringLen
= DIB
.createAutoVariable(Scope
, StrName
, F
, 0, nullptr,
319 false, DINode::FlagZero
, 0);
320 auto getDIExpression
= [&DIB
](int offset
) {
321 SmallVector
<uint64_t, 4> ops
;
322 ops
.push_back(llvm::dwarf::DW_OP_push_object_address
);
323 DIExpression::appendOffset(ops
, offset
);
324 ops
.push_back(llvm::dwarf::DW_OP_deref
);
326 return DIB
.createExpression(ops
);
328 DIExpression
*StringLocationExp
= getDIExpression(1);
329 DIStringType
*StringType
=
330 DIB
.createStringType(StrName
, StringLen
, StringLocationExp
);
332 EXPECT_TRUE(isa_and_nonnull
<DIStringType
>(StringType
));
333 EXPECT_EQ(StringType
->getName(), StrName
);
334 EXPECT_EQ(StringType
->getStringLength(), StringLen
);
335 EXPECT_EQ(StringType
->getStringLocationExp(), StringLocationExp
);
337 StringRef StrNameExp
= "stringexp";
338 DIExpression
*StringLengthExp
= getDIExpression(2);
339 DIStringType
*StringTypeExp
=
340 DIB
.createStringType(StrNameExp
, StringLengthExp
, StringLocationExp
);
342 EXPECT_TRUE(isa_and_nonnull
<DIStringType
>(StringTypeExp
));
343 EXPECT_EQ(StringTypeExp
->getName(), StrNameExp
);
344 EXPECT_EQ(StringTypeExp
->getStringLocationExp(), StringLocationExp
);
345 EXPECT_EQ(StringTypeExp
->getStringLengthExp(), StringLengthExp
);
348 TEST(DIBuilder
, DIEnumerator
) {
350 std::unique_ptr
<Module
> M(new Module("MyModule", Ctx
));
352 APSInt
I1(APInt(32, 1));
353 APSInt
I2(APInt(33, 1));
355 auto *E
= DIEnumerator::get(Ctx
, I1
, I1
.isSigned(), "name");
358 auto *E1
= DIEnumerator::getIfExists(Ctx
, I1
, I1
.isSigned(), "name");
361 auto *E2
= DIEnumerator::getIfExists(Ctx
, I2
, I1
.isSigned(), "name");
365 TEST(DbgAssignIntrinsicTest
, replaceVariableLocationOp
) {
367 std::unique_ptr
<Module
> M
= parseIR(C
, R
"(
368 define dso_local void @fun(i32 %v1, ptr %p1, ptr %p2) !dbg !7 {
370 call void @llvm.dbg.assign(metadata i32 %v1, metadata !14, metadata !DIExpression(), metadata !17, metadata ptr %p1, metadata !DIExpression()), !dbg !16
374 declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata)
377 !llvm.module.flags = !{!3}
379 !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version
14.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
380 !1 = !DIFile(filename: "test
.cpp
", directory: "/")
381 !3 = !{i32 2, !"Debug Info Version
", i32 3}
382 !7 = distinct !DISubprogram(name: "fun
", linkageName: "fun
", scope: !1, file: !1, line: 2, type: !8, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
383 !8 = !DISubroutineType(types: !9)
385 !10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
387 !14 = !DILocalVariable(name: "Local
", scope: !7, file: !1, line: 3, type: !10)
388 !16 = !DILocation(line: 0, scope: !7)
389 !17 = distinct !DIAssignID()
391 // Check the test IR isn't malformed.
394 Function
&Fun
= *M
->getFunction("fun");
395 Value
*V1
= Fun
.getArg(0);
396 Value
*P1
= Fun
.getArg(1);
397 Value
*P2
= Fun
.getArg(2);
398 DbgAssignIntrinsic
*DAI
= cast
<DbgAssignIntrinsic
>(Fun
.begin()->begin());
399 ASSERT_TRUE(V1
== DAI
->getVariableLocationOp(0));
400 ASSERT_TRUE(P1
== DAI
->getAddress());
402 #define TEST_REPLACE(Old, New, ExpectedValue, ExpectedAddr) \
403 DAI->replaceVariableLocationOp(Old, New); \
404 EXPECT_EQ(DAI->getVariableLocationOp(0), ExpectedValue); \
405 EXPECT_EQ(DAI->getAddress(), ExpectedAddr);
407 // Replace address only.
408 TEST_REPLACE(/*Old*/ P1
, /*New*/ P2
, /*Value*/ V1
, /*Address*/ P2
);
409 // Replace value only.
410 TEST_REPLACE(/*Old*/ V1
, /*New*/ P2
, /*Value*/ P2
, /*Address*/ P2
);
412 TEST_REPLACE(/*Old*/ P2
, /*New*/ P1
, /*Value*/ P1
, /*Address*/ P1
);
414 // Replace address only, value uses a DIArgList.
415 // Value = {DIArgList(V1)}, Addr = P1.
416 DAI
->setRawLocation(DIArgList::get(C
, ValueAsMetadata::get(V1
)));
417 DAI
->setExpression(DIExpression::get(
418 C
, {dwarf::DW_OP_LLVM_arg
, 0, dwarf::DW_OP_stack_value
}));
419 TEST_REPLACE(/*Old*/ P1
, /*New*/ P2
, /*Value*/ V1
, /*Address*/ P2
);
423 TEST(AssignmentTrackingTest
, Utils
) {
424 // Test the assignment tracking utils defined in DebugInfo.h namespace at {}.
426 // getAssignmentInsts
427 // getAssignmentMarkers
431 // The input IR includes two functions, fun1 and fun2. Both contain an alloca
432 // with a DIAssignID tag. fun1's alloca is linked to two llvm.dbg.assign
433 // intrinsics, one of which is for an inlined variable and appears before the
437 std::unique_ptr
<Module
> M
= parseIR(C
, R
"(
438 define dso_local void @fun1() !dbg !7 {
440 call void @llvm.dbg.assign(metadata i32 undef, metadata !10, metadata !DIExpression(), metadata !12, metadata i32 undef, metadata !DIExpression()), !dbg !13
441 %local = alloca i32, align 4, !DIAssignID !12
442 call void @llvm.dbg.assign(metadata i32 undef, metadata !16, metadata !DIExpression(), metadata !12, metadata i32 undef, metadata !DIExpression()), !dbg !15
446 define dso_local void @fun2() !dbg !17 {
448 %local = alloca i32, align 4, !DIAssignID !20
449 call void @llvm.dbg.assign(metadata i32 undef, metadata !18, metadata !DIExpression(), metadata !20, metadata i32 undef, metadata !DIExpression()), !dbg !19
453 define dso_local void @fun3() !dbg !21 {
455 %local = alloca i32, align 4, !DIAssignID !24
456 call void @llvm.dbg.assign(metadata i32 undef, metadata !22, metadata !DIExpression(), metadata !24, metadata i32* undef, metadata !DIExpression()), !dbg !23
460 declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata)
463 !llvm.module.flags = !{!3, !4, !5}
466 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version
14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
467 !1 = !DIFile(filename: "test
.c
", directory: "/")
469 !3 = !{i32 7, !"Dwarf Version
", i32 4}
470 !4 = !{i32 2, !"Debug Info Version
", i32 3}
471 !5 = !{i32 1, !"wchar_size
", i32 4}
472 !6 = !{!"clang version
14.0.0"}
473 !7 = distinct !DISubprogram(name: "fun1
", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
474 !8 = !DISubroutineType(types: !9)
476 !10 = !DILocalVariable(name: "local3
", scope: !14, file: !1, line: 2, type: !11)
477 !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
478 !12 = distinct !DIAssignID()
479 !13 = !DILocation(line: 5, column: 1, scope: !14, inlinedAt: !15)
480 !14 = distinct !DISubprogram(name: "inline", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
481 !15 = !DILocation(line: 3, column: 1, scope: !7)
482 !16 = !DILocalVariable(name: "local1
", scope: !7, file: !1, line: 2, type: !11)
483 !17 = distinct !DISubprogram(name: "fun2
", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
484 !18 = !DILocalVariable(name: "local2
", scope: !17, file: !1, line: 2, type: !11)
485 !19 = !DILocation(line: 4, column: 1, scope: !17)
486 !20 = distinct !DIAssignID()
487 !21 = distinct !DISubprogram(name: "fun3
", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
488 !22 = !DILocalVariable(name: "local4
", scope: !21, file: !1, line: 2, type: !11)
489 !23 = !DILocation(line: 4, column: 1, scope: !21)
490 !24 = distinct !DIAssignID()
493 // Check the test IR isn't malformed.
496 Function
&Fun1
= *M
->getFunction("fun1");
497 Instruction
&Alloca
= *Fun1
.getEntryBlock().getFirstNonPHIOrDbg();
499 // 1. Check the Instruction <-> Intrinsic mappings work in fun1.
501 // Check there are two llvm.dbg.assign intrinsics linked to Alloca.
502 auto CheckFun1Mapping
= [&Alloca
]() {
503 auto Markers
= at::getAssignmentMarkers(&Alloca
);
504 EXPECT_TRUE(std::distance(Markers
.begin(), Markers
.end()) == 2);
505 // Check those two entries are distinct.
506 DbgAssignIntrinsic
*First
= *Markers
.begin();
507 DbgAssignIntrinsic
*Second
= *std::next(Markers
.begin());
508 EXPECT_NE(First
, Second
);
510 // Check that we can get back to Alloca from each llvm.dbg.assign.
511 for (auto *DAI
: Markers
) {
512 auto Insts
= at::getAssignmentInsts(DAI
);
513 // Check there is exactly one instruction linked to each intrinsic. Use
514 // ASSERT_TRUE because we're going to dereference the begin iterator.
515 ASSERT_TRUE(std::distance(Insts
.begin(), Insts
.end()) == 1);
516 EXPECT_FALSE(Insts
.empty());
517 // Check the linked instruction is Alloca.
518 Instruction
*LinkedInst
= *Insts
.begin();
519 EXPECT_EQ(LinkedInst
, &Alloca
);
524 // 2. Check DIAssignID RAUW replaces attachments and uses.
527 cast_or_null
<DIAssignID
>(Alloca
.getMetadata(LLVMContext::MD_DIAssignID
));
528 DIAssignID
*New
= DIAssignID::getDistinct(C
);
529 ASSERT_TRUE(Old
&& New
&& New
!= Old
);
531 // Check fun1's alloca and intrinsics have been updated and the mapping still
533 EXPECT_EQ(New
, cast_or_null
<DIAssignID
>(
534 Alloca
.getMetadata(LLVMContext::MD_DIAssignID
)));
537 // Check that fun2's alloca and intrinsic have not not been updated.
538 Instruction
&Fun2Alloca
=
539 *M
->getFunction("fun2")->getEntryBlock().getFirstNonPHIOrDbg();
540 DIAssignID
*Fun2ID
= cast_or_null
<DIAssignID
>(
541 Fun2Alloca
.getMetadata(LLVMContext::MD_DIAssignID
));
542 EXPECT_NE(New
, Fun2ID
);
543 auto Fun2Markers
= at::getAssignmentMarkers(&Fun2Alloca
);
544 ASSERT_TRUE(std::distance(Fun2Markers
.begin(), Fun2Markers
.end()) == 1);
545 auto Fun2Insts
= at::getAssignmentInsts(*Fun2Markers
.begin());
546 ASSERT_TRUE(std::distance(Fun2Insts
.begin(), Fun2Insts
.end()) == 1);
547 EXPECT_EQ(*Fun2Insts
.begin(), &Fun2Alloca
);
549 // 3. Check that deleting dbg.assigns from a specific instruction works.
550 Instruction
&Fun3Alloca
=
551 *M
->getFunction("fun3")->getEntryBlock().getFirstNonPHIOrDbg();
552 auto Fun3Markers
= at::getAssignmentMarkers(&Fun3Alloca
);
553 ASSERT_TRUE(std::distance(Fun3Markers
.begin(), Fun3Markers
.end()) == 1);
554 at::deleteAssignmentMarkers(&Fun3Alloca
);
555 Fun3Markers
= at::getAssignmentMarkers(&Fun3Alloca
);
556 EXPECT_EQ(Fun3Markers
.empty(), true);
558 // 4. Check that deleting works and applies only to the target function.
559 at::deleteAll(&Fun1
);
560 // There should now only be the alloca and ret in fun1.
561 EXPECT_EQ(Fun1
.begin()->size(), 2u);
562 // fun2's alloca should have the same DIAssignID and remain linked to its
564 EXPECT_EQ(Fun2ID
, cast_or_null
<DIAssignID
>(
565 Fun2Alloca
.getMetadata(LLVMContext::MD_DIAssignID
)));
566 EXPECT_FALSE(at::getAssignmentMarkers(&Fun2Alloca
).empty());
569 TEST(IRBuilder
, GetSetInsertionPointWithEmptyBasicBlock
) {
571 std::unique_ptr
<BasicBlock
> BB(BasicBlock::Create(C
, "start"));
572 Module
*M
= new Module("module", C
);
573 IRBuilder
<> Builder(BB
.get());
574 Function
*DbgDeclare
= Intrinsic::getDeclaration(M
, Intrinsic::dbg_declare
);
575 Value
*DIV
= MetadataAsValue::get(C
, (Metadata
*)nullptr);
576 SmallVector
<Value
*, 3> Args
= {DIV
, DIV
, DIV
};
577 Builder
.CreateCall(DbgDeclare
, Args
);
578 auto IP
= BB
->getFirstInsertionPt();
579 Builder
.SetInsertPoint(BB
.get(), IP
);
582 TEST(AssignmentTrackingTest
, InstrMethods
) {
583 // Test the assignment tracking Instruction methods.
585 // Instruction::mergeDIAssignID
588 std::unique_ptr
<Module
> M
= parseIR(C
, R
"(
589 define dso_local void @fun() #0 !dbg !8 {
591 %Local = alloca [2 x i32], align 4, !DIAssignID !12
592 call void @llvm.dbg.assign(metadata i1 undef, metadata !13, metadata !DIExpression(), metadata !12, metadata [2 x i32]* %Local, metadata !DIExpression()), !dbg !18
593 %arrayidx = getelementptr inbounds [2 x i32], [2 x i32]* %Local, i64 0, i64 0, !dbg !19
594 store i32 5, i32* %arrayidx, align 4, !dbg !20, !DIAssignID !21
595 call void @llvm.dbg.assign(metadata i32 5, metadata !13, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32), metadata !21, metadata i32* %arrayidx, metadata !DIExpression()), !dbg !18
596 %arrayidx1 = getelementptr inbounds [2 x i32], [2 x i32]* %Local, i64 0, i64 1, !dbg !22
597 store i32 6, i32* %arrayidx1, align 4, !dbg !23, !DIAssignID !24
598 call void @llvm.dbg.assign(metadata i32 6, metadata !13, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32), metadata !24, metadata i32* %arrayidx1, metadata !DIExpression()), !dbg !18
602 declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata) #1
605 !llvm.module.flags = !{!2, !3, !4, !5, !6}
608 !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version
14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
609 !1 = !DIFile(filename: "test
.cpp
", directory: "/")
610 !2 = !{i32 7, !"Dwarf Version
", i32 5}
611 !3 = !{i32 2, !"Debug Info Version
", i32 3}
612 !4 = !{i32 1, !"wchar_size
", i32 4}
613 !5 = !{i32 7, !"uwtable
", i32 1}
614 !6 = !{i32 7, !"frame
-pointer
", i32 2}
615 !7 = !{!"clang version
14.0.0"}
616 !8 = distinct !DISubprogram(name: "fun
", linkageName: "fun
", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !11)
617 !9 = !DISubroutineType(types: !10)
620 !12 = distinct !DIAssignID()
621 !13 = !DILocalVariable(name: "Local
", scope: !8, file: !1, line: 2, type: !14)
622 !14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !15, size: 64, elements: !16)
623 !15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
625 !17 = !DISubrange(count: 2)
626 !18 = !DILocation(line: 0, scope: !8)
627 !19 = !DILocation(line: 3, column: 3, scope: !8)
628 !20 = !DILocation(line: 3, column: 12, scope: !8)
629 !21 = distinct !DIAssignID()
630 !22 = !DILocation(line: 4, column: 3, scope: !8)
631 !23 = !DILocation(line: 4, column: 12, scope: !8)
632 !24 = distinct !DIAssignID()
633 !25 = !DILocation(line: 5, column: 1, scope: !8)
636 // Check the test IR isn't malformed.
638 Function
&Fun
= *M
->getFunction("fun");
639 SmallVector
<Instruction
*> Stores
;
640 for (auto &BB
: Fun
) {
642 if (isa
<StoreInst
>(&I
))
643 Stores
.push_back(&I
);
647 // The test requires (at least) 2 stores.
648 ASSERT_TRUE(Stores
.size() == 2);
649 // Use SetVectors to check that the attachments and markers are unique
650 // (another test requirement).
651 SetVector
<Metadata
*> OrigIDs
;
652 SetVector
<DbgAssignIntrinsic
*> Markers
;
653 for (const Instruction
*SI
: Stores
) {
654 Metadata
*ID
= SI
->getMetadata(LLVMContext::MD_DIAssignID
);
655 ASSERT_TRUE(OrigIDs
.insert(ID
));
656 ASSERT_TRUE(ID
!= nullptr);
657 auto Range
= at::getAssignmentMarkers(SI
);
658 ASSERT_TRUE(std::distance(Range
.begin(), Range
.end()) == 1);
659 ASSERT_TRUE(Markers
.insert(*Range
.begin()));
662 // Test 1 - mergeDIAssignID.
664 // Input store0->mergeDIAssignID(store1)
665 // ----- -------------------------
666 // store0 !x store0 !x
667 // dbg.assign0 !x dbg.assign !x
668 // store1 !y store1 !x
669 // dbg.assign1 !y dbg.assign1 !x
671 Stores
[0]->mergeDIAssignID(Stores
[1]);
672 // Check that the stores share the same ID.
673 Metadata
*NewID0
= Stores
[0]->getMetadata(LLVMContext::MD_DIAssignID
);
674 Metadata
*NewID1
= Stores
[1]->getMetadata(LLVMContext::MD_DIAssignID
);
675 EXPECT_NE(NewID0
, nullptr);
676 EXPECT_EQ(NewID0
, NewID1
);
677 EXPECT_EQ(Markers
[0]->getAssignID(), NewID0
);
678 EXPECT_EQ(Markers
[1]->getAssignID(), NewID0
);
681 // Test 2 - mergeDIAssignID.
683 // Input store0->mergeDIAssignID(store1)
684 // ----- -------------------------
685 // store0 !x store0 !x
686 // dbg.assign0 !x dbg.assign !x
689 Stores
[1]->setMetadata(LLVMContext::MD_DIAssignID
, nullptr);
690 Stores
[0]->mergeDIAssignID(Stores
[1]);
691 // Check that store1 doesn't get a new ID.
692 Metadata
*NewID0
= Stores
[0]->getMetadata(LLVMContext::MD_DIAssignID
);
693 Metadata
*NewID1
= Stores
[1]->getMetadata(LLVMContext::MD_DIAssignID
);
694 EXPECT_NE(NewID0
, nullptr);
695 EXPECT_EQ(NewID1
, nullptr);
696 EXPECT_EQ(Markers
[0]->getAssignID(), NewID0
);
699 // Test 3 - mergeDIAssignID.
701 // Input store1->mergeDIAssignID(store0)
702 // ----- -------------------------
703 // store0 !x store0 !x
704 // dbg.assign0 !x dbg.assign !x
707 Stores
[1]->setMetadata(LLVMContext::MD_DIAssignID
, nullptr);
708 Stores
[1]->mergeDIAssignID(Stores
[0]);
709 // Check that the stores share the same ID (note store1 starts with none).
710 Metadata
*NewID0
= Stores
[0]->getMetadata(LLVMContext::MD_DIAssignID
);
711 Metadata
*NewID1
= Stores
[1]->getMetadata(LLVMContext::MD_DIAssignID
);
712 EXPECT_NE(NewID0
, nullptr);
713 EXPECT_EQ(NewID0
, NewID1
);
714 EXPECT_EQ(Markers
[0]->getAssignID(), NewID0
);
717 // Test 4 - mergeDIAssignID.
719 // Input store1->mergeDIAssignID(store0)
720 // ----- -------------------------
721 // store0 !x store0 !x
722 // dbg.assign0 !x dbg.assign !x
723 // store1 !x store1 !x
725 Stores
[0]->mergeDIAssignID(Stores
[1]);
726 // Check that the stores share the same ID.
727 Metadata
*NewID0
= Stores
[0]->getMetadata(LLVMContext::MD_DIAssignID
);
728 Metadata
*NewID1
= Stores
[1]->getMetadata(LLVMContext::MD_DIAssignID
);
729 EXPECT_NE(NewID0
, nullptr);
730 EXPECT_EQ(NewID0
, NewID1
);
731 EXPECT_EQ(Markers
[0]->getAssignID(), NewID0
);
734 // Test 5 - dropUnknownNonDebugMetadata.
736 // Input store0->dropUnknownNonDebugMetadata()
737 // ----- -------------------------
738 // store0 !x store0 !x
740 Stores
[0]->dropUnknownNonDebugMetadata();
741 Metadata
*NewID0
= Stores
[0]->getMetadata(LLVMContext::MD_DIAssignID
);
742 EXPECT_NE(NewID0
, nullptr);