[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / llvm / unittests / IR / DebugInfoTest.cpp
blob84ed73333416c1193b6c949b777ffd21835e96e8
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 //===----------------------------------------------------------------------===//
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"
24 using namespace llvm;
26 static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
27 SMDiagnostic Err;
28 std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
29 if (!Mod)
30 Err.print("DebugInfoTest", errs());
31 return Mod;
34 namespace {
36 TEST(DINodeTest, getFlag) {
37 // Some valid flags.
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) {
56 // Some valid flags.
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) {
82 // Some valid flags.
83 #define CHECK_SPLIT(FLAGS, VECTOR, REMAINDER) \
84 { \
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},
94 DINode::FlagZero);
95 DINode::DIFlags Flags[] = {DINode::FlagFwdDecl, DINode::FlagVector};
96 CHECK_SPLIT(DINode::FlagFwdDecl | DINode::FlagVector, Flags,
97 DINode::FlagZero);
98 CHECK_SPLIT(DINode::FlagZero, {}, DINode::FlagZero);
99 #undef CHECK_SPLIT
102 TEST(StripTest, LoopMetadata) {
103 LLVMContext C;
104 std::unique_ptr<Module> M = parseIR(C, R"(
105 define void @f() !dbg !5 {
106 ret void, !dbg !10, !llvm.loop !11
109 !llvm.dbg.cu = !{!0}
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: "/")
115 !2 = !{}
116 !3 = !{i32 1}
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)
120 !7 = !{!8}
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}
125 )");
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))
135 ->getScope()
136 ->getSubprogram()
137 ->getUnit()
138 ->getEmissionKind();
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) {
155 LLVMContext C;
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
160 ret i16 0, !dbg !11
162 declare void @llvm.dbg.value(metadata, metadata, metadata) #0
163 attributes #0 = { nounwind readnone speculatable willreturn }
165 !llvm.dbg.cu = !{!0}
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: "/")
170 !2 = !{}
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)
174 !8 = !{!9}
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)
178 )");
180 // Find %b = add ...
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.
188 I.eraseFromParent();
189 EXPECT_EQ(DVIs[0]->getNumVariableLocationOps(), 1u);
190 EXPECT_TRUE(isa<UndefValue>(DVIs[0]->getValue(0)));
193 TEST(DbgVariableIntrinsic, EmptyMDIsKillLocation) {
194 LLVMContext Ctx;
195 std::unique_ptr<Module> M = parseIR(Ctx, R"(
196 define dso_local void @fun() local_unnamed_addr #0 !dbg !9 {
197 entry:
198 call void @llvm.dbg.declare(metadata !{}, metadata !13, metadata !DIExpression()), !dbg !16
199 ret void, !dbg !16
202 declare void @llvm.dbg.declare(metadata, metadata, metadata)
204 !llvm.dbg.cu = !{!0}
205 !llvm.module.flags = !{!2, !3}
206 !llvm.ident = !{!8}
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)
215 !11 = !{null}
216 !12 = !{!13}
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)
220 )");
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) {
235 LLVMContext Ctx;
236 std::unique_ptr<Module> M(new Module("MyModule", Ctx));
237 DIBuilder DIB(*M);
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());
247 Source = "";
248 F = DIB.createFile("main.c", "/", Checksum, Source);
249 EXPECT_EQ(Source, F->getSource());
252 TEST(DIBuilder, CreateFortranArrayTypeWithAttributes) {
253 LLVMContext Ctx;
254 std::unique_ptr<Module> M(new Module("MyModule", Ctx));
255 DIBuilder DIB(*M);
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,
283 Allocated, Rank);
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) {
296 LLVMContext Ctx;
297 std::unique_ptr<Module> M(new Module("MyModule", Ctx));
298 DIBuilder DIB(*M);
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) {
310 LLVMContext Ctx;
311 std::unique_ptr<Module> M(new Module("MyModule", Ctx));
312 DIBuilder DIB(*M);
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) {
349 LLVMContext Ctx;
350 std::unique_ptr<Module> M(new Module("MyModule", Ctx));
351 DIBuilder DIB(*M);
352 APSInt I1(APInt(32, 1));
353 APSInt I2(APInt(33, 1));
355 auto *E = DIEnumerator::get(Ctx, I1, I1.isSigned(), "name");
356 EXPECT_TRUE(E);
358 auto *E1 = DIEnumerator::getIfExists(Ctx, I1, I1.isSigned(), "name");
359 EXPECT_TRUE(E1);
361 auto *E2 = DIEnumerator::getIfExists(Ctx, I2, I1.isSigned(), "name");
362 EXPECT_FALSE(E2);
365 TEST(DbgAssignIntrinsicTest, replaceVariableLocationOp) {
366 LLVMContext C;
367 std::unique_ptr<Module> M = parseIR(C, R"(
368 define dso_local void @fun(i32 %v1, ptr %p1, ptr %p2) !dbg !7 {
369 entry:
370 call void @llvm.dbg.assign(metadata i32 %v1, metadata !14, metadata !DIExpression(), metadata !17, metadata ptr %p1, metadata !DIExpression()), !dbg !16
371 ret void
374 declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata)
376 !llvm.dbg.cu = !{!0}
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)
384 !9 = !{null}
385 !10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
386 !11 = !{}
387 !14 = !DILocalVariable(name: "Local", scope: !7, file: !1, line: 3, type: !10)
388 !16 = !DILocation(line: 0, scope: !7)
389 !17 = distinct !DIAssignID()
390 )");
391 // Check the test IR isn't malformed.
392 ASSERT_TRUE(M);
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);
411 // Replace both.
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);
420 #undef TEST_REPLACE
423 TEST(AssignmentTrackingTest, Utils) {
424 // Test the assignment tracking utils defined in DebugInfo.h namespace at {}.
425 // This includes:
426 // getAssignmentInsts
427 // getAssignmentMarkers
428 // RAUW
429 // deleteAll
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
434 // alloca.
436 LLVMContext C;
437 std::unique_ptr<Module> M = parseIR(C, R"(
438 define dso_local void @fun1() !dbg !7 {
439 entry:
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
443 ret void, !dbg !15
446 define dso_local void @fun2() !dbg !17 {
447 entry:
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
450 ret void, !dbg !19
453 define dso_local void @fun3() !dbg !21 {
454 entry:
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
457 ret void
460 declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata)
462 !llvm.dbg.cu = !{!0}
463 !llvm.module.flags = !{!3, !4, !5}
464 !llvm.ident = !{!6}
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: "/")
468 !2 = !{}
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)
475 !9 = !{null}
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()
491 )");
493 // Check the test IR isn't malformed.
494 ASSERT_TRUE(M);
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);
522 CheckFun1Mapping();
524 // 2. Check DIAssignID RAUW replaces attachments and uses.
526 DIAssignID *Old =
527 cast_or_null<DIAssignID>(Alloca.getMetadata(LLVMContext::MD_DIAssignID));
528 DIAssignID *New = DIAssignID::getDistinct(C);
529 ASSERT_TRUE(Old && New && New != Old);
530 at::RAUW(Old, New);
531 // Check fun1's alloca and intrinsics have been updated and the mapping still
532 // works.
533 EXPECT_EQ(New, cast_or_null<DIAssignID>(
534 Alloca.getMetadata(LLVMContext::MD_DIAssignID)));
535 CheckFun1Mapping();
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
563 // llvm.dbg.assign.
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) {
570 LLVMContext C;
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.
584 // This includes:
585 // Instruction::mergeDIAssignID
587 LLVMContext C;
588 std::unique_ptr<Module> M = parseIR(C, R"(
589 define dso_local void @fun() #0 !dbg !8 {
590 entry:
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
599 ret void, !dbg !25
602 declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata) #1
604 !llvm.dbg.cu = !{!0}
605 !llvm.module.flags = !{!2, !3, !4, !5, !6}
606 !llvm.ident = !{!7}
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)
618 !10 = !{null}
619 !11 = !{}
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)
624 !16 = !{!17}
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)
634 )");
636 // Check the test IR isn't malformed.
637 ASSERT_TRUE(M);
638 Function &Fun = *M->getFunction("fun");
639 SmallVector<Instruction *> Stores;
640 for (auto &BB : Fun) {
641 for (auto &I : BB) {
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
687 // store1 store1
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
705 // store1 store1 !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);
746 } // end namespace