1448 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/IR/DebugInfo.h"10#include "../lib/IR/LLVMContextImpl.h"11#include "llvm/ADT/APSInt.h"12#include "llvm/AsmParser/Parser.h"13#include "llvm/IR/DIBuilder.h"14#include "llvm/IR/DebugInfoMetadata.h"15#include "llvm/IR/DebugProgramInstruction.h"16#include "llvm/IR/IRBuilder.h"17#include "llvm/IR/IntrinsicInst.h"18#include "llvm/IR/LLVMContext.h"19#include "llvm/IR/Metadata.h"20#include "llvm/IR/Module.h"21#include "llvm/IR/Verifier.h"22#include "llvm/Support/Compiler.h"23#include "llvm/Support/SourceMgr.h"24#include "llvm/Transforms/Utils/Local.h"25 26#include "gtest/gtest.h"27 28using namespace llvm;29 30static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {31 SMDiagnostic Err;32 std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);33 if (!Mod)34 Err.print("DebugInfoTest", errs());35 return Mod;36}37 38namespace {39 40TEST(DINodeTest, getFlag) {41 // Some valid flags.42 EXPECT_EQ(DINode::FlagPublic, DINode::getFlag("DIFlagPublic"));43 EXPECT_EQ(DINode::FlagProtected, DINode::getFlag("DIFlagProtected"));44 EXPECT_EQ(DINode::FlagPrivate, DINode::getFlag("DIFlagPrivate"));45 EXPECT_EQ(DINode::FlagVector, DINode::getFlag("DIFlagVector"));46 EXPECT_EQ(DINode::FlagRValueReference,47 DINode::getFlag("DIFlagRValueReference"));48 49 // FlagAccessibility shouldn't work.50 EXPECT_EQ(0u, DINode::getFlag("DIFlagAccessibility"));51 52 // Some other invalid strings.53 EXPECT_EQ(0u, DINode::getFlag("FlagVector"));54 EXPECT_EQ(0u, DINode::getFlag("Vector"));55 EXPECT_EQ(0u, DINode::getFlag("other things"));56 EXPECT_EQ(0u, DINode::getFlag("DIFlagOther"));57}58 59TEST(DINodeTest, getFlagString) {60 // Some valid flags.61 EXPECT_EQ(StringRef("DIFlagPublic"),62 DINode::getFlagString(DINode::FlagPublic));63 EXPECT_EQ(StringRef("DIFlagProtected"),64 DINode::getFlagString(DINode::FlagProtected));65 EXPECT_EQ(StringRef("DIFlagPrivate"),66 DINode::getFlagString(DINode::FlagPrivate));67 EXPECT_EQ(StringRef("DIFlagVector"),68 DINode::getFlagString(DINode::FlagVector));69 EXPECT_EQ(StringRef("DIFlagRValueReference"),70 DINode::getFlagString(DINode::FlagRValueReference));71 72 // FlagAccessibility actually equals FlagPublic.73 EXPECT_EQ(StringRef("DIFlagPublic"),74 DINode::getFlagString(DINode::FlagAccessibility));75 76 // Some other invalid flags.77 EXPECT_EQ(StringRef(),78 DINode::getFlagString(DINode::FlagPublic | DINode::FlagVector));79 EXPECT_EQ(StringRef(), DINode::getFlagString(DINode::FlagFwdDecl |80 DINode::FlagArtificial));81 EXPECT_EQ(StringRef(),82 DINode::getFlagString(static_cast<DINode::DIFlags>(0xffff)));83}84 85TEST(DINodeTest, splitFlags) {86// Some valid flags.87#define CHECK_SPLIT(FLAGS, VECTOR, REMAINDER) \88 { \89 SmallVector<DINode::DIFlags, 8> V; \90 EXPECT_EQ(REMAINDER, DINode::splitFlags(FLAGS, V)); \91 EXPECT_TRUE(ArrayRef(V).equals(VECTOR)); \92 }93 CHECK_SPLIT(DINode::FlagPublic, {DINode::FlagPublic}, DINode::FlagZero);94 CHECK_SPLIT(DINode::FlagProtected, {DINode::FlagProtected}, DINode::FlagZero);95 CHECK_SPLIT(DINode::FlagPrivate, {DINode::FlagPrivate}, DINode::FlagZero);96 CHECK_SPLIT(DINode::FlagVector, {DINode::FlagVector}, DINode::FlagZero);97 CHECK_SPLIT(DINode::FlagRValueReference, {DINode::FlagRValueReference},98 DINode::FlagZero);99 DINode::DIFlags Flags[] = {DINode::FlagFwdDecl, DINode::FlagVector};100 CHECK_SPLIT(DINode::FlagFwdDecl | DINode::FlagVector, Flags,101 DINode::FlagZero);102 CHECK_SPLIT(DINode::FlagZero, {}, DINode::FlagZero);103#undef CHECK_SPLIT104}105 106TEST(StripTest, LoopMetadata) {107 LLVMContext C;108 std::unique_ptr<Module> M = parseIR(C, R"(109 define void @f() !dbg !5 {110 ret void, !dbg !10, !llvm.loop !11111 }112 113 !llvm.dbg.cu = !{!0}114 !llvm.debugify = !{!3, !3}115 !llvm.module.flags = !{!4}116 117 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)118 !1 = !DIFile(filename: "loop.ll", directory: "/")119 !2 = !{}120 !3 = !{i32 1}121 !4 = !{i32 2, !"Debug Info Version", i32 3}122 !5 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !7)123 !6 = !DISubroutineType(types: !2)124 !7 = !{!8}125 !8 = !DILocalVariable(name: "1", scope: !5, file: !1, line: 1, type: !9)126 !9 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned)127 !10 = !DILocation(line: 1, column: 1, scope: !5)128 !11 = distinct !{!11, !10, !10}129)");130 131 // Look up the debug info emission kind for the CU via the loop metadata132 // attached to the terminator. If, when stripping non-line table debug info,133 // we update the terminator's metadata correctly, we should be able to134 // observe the change in emission kind for the CU.135 auto getEmissionKind = [&]() {136 Instruction &I = *M->getFunction("f")->getEntryBlock().getFirstNonPHIIt();137 MDNode *LoopMD = I.getMetadata(LLVMContext::MD_loop);138 return cast<DILocation>(LoopMD->getOperand(1))139 ->getScope()140 ->getSubprogram()141 ->getUnit()142 ->getEmissionKind();143 };144 145 EXPECT_EQ(getEmissionKind(), DICompileUnit::FullDebug);146 147 bool Changed = stripNonLineTableDebugInfo(*M);148 EXPECT_TRUE(Changed);149 150 EXPECT_EQ(getEmissionKind(), DICompileUnit::LineTablesOnly);151 152 bool BrokenDebugInfo = false;153 bool HardError = verifyModule(*M, &errs(), &BrokenDebugInfo);154 EXPECT_FALSE(HardError);155 EXPECT_FALSE(BrokenDebugInfo);156}157 158TEST(MetadataTest, DeleteInstUsedByDbgRecord) {159 LLVMContext C;160 std::unique_ptr<Module> M = parseIR(C, R"(161 define i16 @f(i16 %a) !dbg !6 {162 %b = add i16 %a, 1, !dbg !11163 call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11164 ret i16 0, !dbg !11165 }166 declare void @llvm.dbg.value(metadata, metadata, metadata) #0167 attributes #0 = { nounwind readnone speculatable willreturn }168 169 !llvm.dbg.cu = !{!0}170 !llvm.module.flags = !{!5}171 172 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)173 !1 = !DIFile(filename: "t.ll", directory: "/")174 !2 = !{}175 !5 = !{i32 2, !"Debug Info Version", i32 3}176 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)177 !7 = !DISubroutineType(types: !2)178 !8 = !{!9}179 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)180 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)181 !11 = !DILocation(line: 1, column: 1, scope: !6)182)");183 184 // Find %b = add ...185 Instruction &I = *M->getFunction("f")->getEntryBlock().getFirstNonPHIIt();186 187 // Find the dbg.value using %b.188 SmallVector<DbgVariableRecord *, 1> DVRs;189 findDbgValues(&I, DVRs);190 191 // Delete %b. The dbg.value should now point to undef.192 I.eraseFromParent();193 EXPECT_EQ(DVRs[0]->getNumVariableLocationOps(), 1u);194 EXPECT_TRUE(isa<UndefValue>(DVRs[0]->getValue(0)));195}196 197TEST(MetadataTest, GlobalConstantMetadataUsedByDbgRecord) {198 LLVMContext C;199 std::unique_ptr<Module> M = parseIR(C, R"(200 @x = dso_local global i32 0, align 4201 declare void @llvm.dbg.value(metadata, metadata, metadata) #0202 203 define i16 @f(i16 %a) !dbg !6 {204 %b = add i16 %a, 1, !dbg !11205 call void @llvm.dbg.declare(metadata ptr @x, metadata !9, metadata !DIExpression()), !dbg !11206 call void @llvm.dbg.value(metadata ptr @x, metadata !9, metadata !DIExpression()), !dbg !11207 ret i16 0, !dbg !11208 }209 210 attributes #0 = { nounwind readnone speculatable willreturn }211 212 !llvm.dbg.cu = !{!0}213 !llvm.module.flags = !{!5}214 215 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)216 !1 = !DIFile(filename: "t.ll", directory: "/")217 !2 = !{}218 !5 = !{i32 2, !"Debug Info Version", i32 3}219 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)220 !7 = !DISubroutineType(types: !2)221 !8 = !{!9}222 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)223 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)224 !11 = !DILocation(line: 1, column: 1, scope: !6)225)");226 227 // Find the global @x228 Value *V = M->getNamedValue("x");229 230 // Find the dbg.value231 auto DVRs = findDVRDeclares(V);232 auto DVRVs = findDVRValues(V);233 234 EXPECT_EQ(DVRs[0]->getNumVariableLocationOps(), 1u);235 EXPECT_TRUE(DVRVs.size() == 1);236 EXPECT_FALSE(isa<UndefValue>(DVRs[0]->getValue(0)));237}238 239TEST(DbgVariableIntrinsic, EmptyMDIsKillLocation) {240 LLVMContext Ctx;241 std::unique_ptr<Module> M = parseIR(Ctx, R"(242 define dso_local void @fun() local_unnamed_addr #0 !dbg !9 {243 entry:244 call void @llvm.dbg.declare(metadata !{}, metadata !13, metadata !DIExpression()), !dbg !16245 ret void, !dbg !16246 }247 248 declare void @llvm.dbg.declare(metadata, metadata, metadata)249 250 !llvm.dbg.cu = !{!0}251 !llvm.module.flags = !{!2, !3}252 !llvm.ident = !{!8}253 254 !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)255 !1 = !DIFile(filename: "test.c", directory: "/")256 !2 = !{i32 7, !"Dwarf Version", i32 5}257 !3 = !{i32 2, !"Debug Info Version", i32 3}258 !8 = !{!"clang version 16.0.0"}259 !9 = distinct !DISubprogram(name: "fun", scope: !1, file: !1, line: 1, type: !10, scopeLine: 1, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12)260 !10 = !DISubroutineType(types: !11)261 !11 = !{null}262 !12 = !{!13}263 !13 = !DILocalVariable(name: "a", scope: !9, file: !1, line: 1, type: !14)264 !14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)265 !16 = !DILocation(line: 1, column: 21, scope: !9)266 )");267 268 bool BrokenDebugInfo = true;269 verifyModule(*M, &errs(), &BrokenDebugInfo);270 ASSERT_FALSE(BrokenDebugInfo);271 272 // Get the dbg.declare.273 Function &F = *cast<Function>(M->getNamedValue("fun"));274 DbgVariableRecord *DbgDeclare =275 cast<DbgVariableRecord>(&*F.front().front().getDbgRecordRange().begin());276 // Check that this form counts as a "no location" marker.277 EXPECT_TRUE(DbgDeclare->isKillLocation());278}279 280// Duplicate of above test, but in DbgVariableRecord representation.281TEST(MetadataTest, DeleteInstUsedByDbgVariableRecord) {282 LLVMContext C;283 284 std::unique_ptr<Module> M = parseIR(C, R"(285 define i16 @f(i16 %a) !dbg !6 {286 %b = add i16 %a, 1, !dbg !11287 call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11288 call void @llvm.dbg.value(metadata !DIArgList(i16 %a, i16 %b), metadata !9, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus)), !dbg !11289 ret i16 0, !dbg !11290 }291 declare void @llvm.dbg.value(metadata, metadata, metadata) #0292 attributes #0 = { nounwind readnone speculatable willreturn }293 294 !llvm.dbg.cu = !{!0}295 !llvm.module.flags = !{!5}296 297 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)298 !1 = !DIFile(filename: "t.ll", directory: "/")299 !2 = !{}300 !5 = !{i32 2, !"Debug Info Version", i32 3}301 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)302 !7 = !DISubroutineType(types: !2)303 !8 = !{!9}304 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)305 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)306 !11 = !DILocation(line: 1, column: 1, scope: !6)307)");308 309 Instruction &I = *M->getFunction("f")->getEntryBlock().getFirstNonPHIIt();310 311 // Find the DbgVariableRecords using %b.312 SmallVector<DbgVariableRecord *, 2> DVRs;313 findDbgValues(&I, DVRs);314 ASSERT_EQ(DVRs.size(), 2u);315 316 // Delete %b. The DbgVariableRecord should now point to undef.317 I.eraseFromParent();318 EXPECT_EQ(DVRs[0]->getNumVariableLocationOps(), 1u);319 EXPECT_TRUE(isa<UndefValue>(DVRs[0]->getVariableLocationOp(0)));320 EXPECT_TRUE(DVRs[0]->isKillLocation());321 EXPECT_EQ(DVRs[1]->getNumVariableLocationOps(), 2u);322 EXPECT_TRUE(isa<UndefValue>(DVRs[1]->getVariableLocationOp(1)));323 EXPECT_TRUE(DVRs[1]->isKillLocation());324}325 326// Ensure that the order of dbg.value intrinsics returned by findDbgValues, and327// their corresponding DbgVariableRecord representation, are consistent.328TEST(MetadataTest, OrderingOfDbgVariableRecords) {329 LLVMContext C;330 std::unique_ptr<Module> M = parseIR(C, R"(331 define i16 @f(i16 %a) !dbg !6 {332 %b = add i16 %a, 1, !dbg !11333 #dbg_value(i16 %b, !9, !DIExpression(), !11)334 #dbg_value(i16 %b, !12, !DIExpression(), !11)335 ret i16 0, !dbg !11336 }337 attributes #0 = { nounwind readnone speculatable willreturn }338 339 !llvm.dbg.cu = !{!0}340 !llvm.module.flags = !{!5}341 342 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)343 !1 = !DIFile(filename: "t.ll", directory: "/")344 !2 = !{}345 !5 = !{i32 2, !"Debug Info Version", i32 3}346 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)347 !7 = !DISubroutineType(types: !2)348 !8 = !{!9}349 !9 = !DILocalVariable(name: "foo", scope: !6, file: !1, line: 1, type: !10)350 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)351 !11 = !DILocation(line: 1, column: 1, scope: !6)352 !12 = !DILocalVariable(name: "bar", scope: !6, file: !1, line: 1, type: !10)353)");354 355 Instruction &I = *M->getFunction("f")->getEntryBlock().getFirstNonPHIIt();356 357 SmallVector<DbgVariableRecord *, 2> DVRs;358 359 findDbgValues(&I, DVRs);360 ASSERT_EQ(DVRs.size(), 2u);361 362 // The correct order of dbg.values is given by their use-list, which becomes363 // the reverse order of creation. Thus the dbg.values should come out as364 // "bar" and then "foo".365 const DILocalVariable *Var0 = DVRs[0]->getVariable();366 EXPECT_TRUE(Var0->getName() == "bar");367 const DILocalVariable *Var1 = DVRs[1]->getVariable();368 EXPECT_TRUE(Var1->getName() == "foo");369 370 M->convertFromNewDbgValues();371}372 373TEST(DIBuilder, CreateFile) {374 LLVMContext Ctx;375 std::unique_ptr<Module> M(new Module("MyModule", Ctx));376 DIBuilder DIB(*M);377 378 DIFile *F = DIB.createFile("main.c", "/");379 EXPECT_EQ(std::nullopt, F->getSource());380 381 std::optional<DIFile::ChecksumInfo<StringRef>> Checksum;382 std::optional<StringRef> Source;383 F = DIB.createFile("main.c", "/", Checksum, Source);384 EXPECT_EQ(Source, F->getSource());385 386 Source = "";387 F = DIB.createFile("main.c", "/", Checksum, Source);388 EXPECT_EQ(Source, F->getSource());389}390 391TEST(DIBuilder, CreateFortranArrayTypeWithAttributes) {392 LLVMContext Ctx;393 std::unique_ptr<Module> M(new Module("MyModule", Ctx));394 DIBuilder DIB(*M);395 396 DISubrange *Subrange = DIB.getOrCreateSubrange(1,1);397 SmallVector<Metadata*, 4> Subranges;398 Subranges.push_back(Subrange);399 DINodeArray Subscripts = DIB.getOrCreateArray(Subranges);400 401 auto getDIExpression = [&DIB](int offset) {402 SmallVector<uint64_t, 4> ops;403 ops.push_back(llvm::dwarf::DW_OP_push_object_address);404 DIExpression::appendOffset(ops, offset);405 ops.push_back(llvm::dwarf::DW_OP_deref);406 407 return DIB.createExpression(ops);408 };409 410 DIFile *F = DIB.createFile("main.c", "/");411 DICompileUnit *CU = DIB.createCompileUnit(412 DISourceLanguageName(dwarf::DW_LANG_C), DIB.createFile("main.c", "/"),413 "llvm-c", true, "", 0);414 415 DIVariable *DataLocation =416 DIB.createTempGlobalVariableFwdDecl(CU, "dl", "_dl", F, 1, nullptr, true);417 DIExpression *Associated = getDIExpression(1);418 DIExpression *Allocated = getDIExpression(2);419 DIExpression *Rank = DIB.createConstantValueExpression(3);420 421 DICompositeType *ArrayType = DIB.createArrayType(0, 0, nullptr, Subscripts,422 DataLocation, Associated,423 Allocated, Rank);424 425 EXPECT_TRUE(isa_and_nonnull<DICompositeType>(ArrayType));426 EXPECT_EQ(ArrayType->getRawDataLocation(), DataLocation);427 EXPECT_EQ(ArrayType->getRawAssociated(), Associated);428 EXPECT_EQ(ArrayType->getRawAllocated(), Allocated);429 EXPECT_EQ(ArrayType->getRawRank(), Rank);430 431 // Avoid memory leak.432 DIVariable::deleteTemporary(DataLocation);433}434 435TEST(DIBuilder, CreateArrayWithBitStride) {436 LLVMContext Ctx;437 std::unique_ptr<Module> M(new Module("MyModule", Ctx));438 DIBuilder DIB(*M);439 440 Type *Int32Ty = Type::getInt32Ty(Ctx);441 Constant *Ci = ConstantInt::get(Int32Ty, 7);442 Metadata *CM = ConstantAsMetadata::get(Ci);443 444 StringRef ArrayNameExp = "AnArray";445 DICompositeType *NamedArray =446 DIB.createArrayType(nullptr, ArrayNameExp, nullptr, 0, 8, 8, nullptr, {},447 nullptr, nullptr, nullptr, nullptr, CM);448 EXPECT_EQ(NamedArray->getTag(), dwarf::DW_TAG_array_type);449 EXPECT_EQ(NamedArray->getRawBitStride(), CM);450 EXPECT_EQ(NamedArray->getBitStrideConst(), Ci);451}452 453TEST(DIBuilder, CreateSetType) {454 LLVMContext Ctx;455 std::unique_ptr<Module> M(new Module("MyModule", Ctx));456 DIBuilder DIB(*M);457 DIScope *Scope = DISubprogram::getDistinct(458 Ctx, nullptr, "", "", nullptr, 0, nullptr, 0, nullptr, 0, 0,459 DINode::FlagZero, DISubprogram::SPFlagZero, nullptr);460 DIType *Type = DIB.createBasicType("Int", 64, dwarf::DW_ATE_signed);461 DIFile *F = DIB.createFile("main.c", "/");462 463 DIDerivedType *SetType = DIB.createSetType(Scope, "set1", F, 1, 64, 64, Type);464 EXPECT_TRUE(isa_and_nonnull<DIDerivedType>(SetType));465}466 467TEST(DIBuilder, CreateStringType) {468 LLVMContext Ctx;469 std::unique_ptr<Module> M(new Module("MyModule", Ctx));470 DIBuilder DIB(*M);471 DIScope *Scope = DISubprogram::getDistinct(472 Ctx, nullptr, "", "", nullptr, 0, nullptr, 0, nullptr, 0, 0,473 DINode::FlagZero, DISubprogram::SPFlagZero, nullptr);474 DIFile *F = DIB.createFile("main.c", "/");475 StringRef StrName = "string";476 DIVariable *StringLen = DIB.createAutoVariable(Scope, StrName, F, 0, nullptr,477 false, DINode::FlagZero, 0);478 auto getDIExpression = [&DIB](int offset) {479 SmallVector<uint64_t, 4> ops;480 ops.push_back(llvm::dwarf::DW_OP_push_object_address);481 DIExpression::appendOffset(ops, offset);482 ops.push_back(llvm::dwarf::DW_OP_deref);483 484 return DIB.createExpression(ops);485 };486 DIExpression *StringLocationExp = getDIExpression(1);487 DIStringType *StringType =488 DIB.createStringType(StrName, StringLen, StringLocationExp);489 490 EXPECT_TRUE(isa_and_nonnull<DIStringType>(StringType));491 EXPECT_EQ(StringType->getName(), StrName);492 EXPECT_EQ(StringType->getStringLength(), StringLen);493 EXPECT_EQ(StringType->getStringLocationExp(), StringLocationExp);494 495 StringRef StrNameExp = "stringexp";496 DIExpression *StringLengthExp = getDIExpression(2);497 DIStringType *StringTypeExp =498 DIB.createStringType(StrNameExp, StringLengthExp, StringLocationExp);499 500 EXPECT_TRUE(isa_and_nonnull<DIStringType>(StringTypeExp));501 EXPECT_EQ(StringTypeExp->getName(), StrNameExp);502 EXPECT_EQ(StringTypeExp->getStringLocationExp(), StringLocationExp);503 EXPECT_EQ(StringTypeExp->getStringLengthExp(), StringLengthExp);504}505 506TEST(DIBuilder, DIEnumerator) {507 LLVMContext Ctx;508 std::unique_ptr<Module> M(new Module("MyModule", Ctx));509 DIBuilder DIB(*M);510 APSInt I1(APInt(32, 1));511 APSInt I2(APInt(33, 1));512 513 auto *E = DIEnumerator::get(Ctx, I1, I1.isSigned(), "name");514 EXPECT_TRUE(E);515 516 auto *E1 = DIEnumerator::getIfExists(Ctx, I1, I1.isSigned(), "name");517 EXPECT_TRUE(E1);518 519 auto *E2 = DIEnumerator::getIfExists(Ctx, I2, I1.isSigned(), "name");520 EXPECT_FALSE(E2);521}522 523TEST(DIBuilder, FixedPointType) {524 LLVMContext Ctx;525 std::unique_ptr<Module> M(new Module("MyModule", Ctx));526 DIBuilder DIB(*M);527 528 DIFixedPointType *Ty = DIB.createBinaryFixedPointType(529 {}, 32, 0, dwarf::DW_ATE_signed_fixed, DINode::FlagZero, -4);530 EXPECT_TRUE(Ty);531 EXPECT_TRUE(Ty->getKind() == DIFixedPointType::FixedPointBinary);532 EXPECT_TRUE(Ty->getFactor() == -4);533 EXPECT_TRUE(Ty->getEncoding() == dwarf::DW_ATE_signed_fixed);534 EXPECT_TRUE(Ty->getTag() == dwarf::DW_TAG_base_type);535 536 Ty = DIB.createDecimalFixedPointType({}, 32, 0, dwarf::DW_ATE_unsigned_fixed,537 DINode::FlagZero, -7);538 EXPECT_TRUE(Ty);539 EXPECT_TRUE(Ty->getKind() == DIFixedPointType::FixedPointDecimal);540 EXPECT_TRUE(Ty->getFactor() == -7);541 EXPECT_TRUE(Ty->getEncoding() == dwarf::DW_ATE_unsigned_fixed);542 EXPECT_TRUE(Ty->getTag() == dwarf::DW_TAG_base_type);543 544 APSInt Num(APInt(32, 1));545 APSInt Denom(APInt(33, 72));546 Ty = DIB.createRationalFixedPointType({}, 32, 0, dwarf::DW_ATE_unsigned_fixed,547 DINode::FlagZero, Num, Denom);548 EXPECT_TRUE(Ty);549 EXPECT_TRUE(Ty->getKind() == DIFixedPointType::FixedPointRational);550 EXPECT_TRUE(Ty->getFactorRaw() == 0);551 EXPECT_TRUE(Ty->getNumerator() == Num);552 EXPECT_TRUE(Ty->getDenominator() == Denom);553 EXPECT_TRUE(Ty->getEncoding() == dwarf::DW_ATE_unsigned_fixed);554 EXPECT_TRUE(Ty->getTag() == dwarf::DW_TAG_base_type);555}556 557TEST(DbgAssignRecordTest, replaceVariableLocationOp) {558 LLVMContext C;559 std::unique_ptr<Module> M = parseIR(C, R"(560 define dso_local void @fun(i32 %v1, ptr %p1, ptr %p2) !dbg !7 {561 entry:562 #dbg_assign(i32 %v1, !14, !DIExpression(), !17, ptr %p1, !DIExpression(), !16)563 ret void564 }565 566 !llvm.dbg.cu = !{!0}567 !llvm.module.flags = !{!3}568 569 !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)570 !1 = !DIFile(filename: "test.cpp", directory: "/")571 !3 = !{i32 2, !"Debug Info Version", i32 3}572 !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)573 !8 = !DISubroutineType(types: !9)574 !9 = !{null}575 !10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)576 !11 = !{}577 !14 = !DILocalVariable(name: "Local", scope: !7, file: !1, line: 3, type: !10)578 !16 = !DILocation(line: 0, scope: !7)579 !17 = distinct !DIAssignID()580 )");581 // Check the test IR isn't malformed.582 ASSERT_TRUE(M);583 584 Function &Fun = *M->getFunction("fun");585 Value *V1 = Fun.getArg(0);586 Value *P1 = Fun.getArg(1);587 Value *P2 = Fun.getArg(2);588 DbgVariableRecord *DbgAssign = cast<DbgVariableRecord>(589 &*Fun.front().front().getDbgRecordRange().begin());590 ASSERT_TRUE(V1 == DbgAssign->getVariableLocationOp(0));591 ASSERT_TRUE(P1 == DbgAssign->getAddress());592 593#define TEST_REPLACE(Old, New, ExpectedValue, ExpectedAddr) \594 DbgAssign->replaceVariableLocationOp(Old, New); \595 EXPECT_EQ(DbgAssign->getVariableLocationOp(0), ExpectedValue); \596 EXPECT_EQ(DbgAssign->getAddress(), ExpectedAddr);597 598 // Replace address only.599 TEST_REPLACE(/*Old*/ P1, /*New*/ P2, /*Value*/ V1, /*Address*/ P2);600 // Replace value only.601 TEST_REPLACE(/*Old*/ V1, /*New*/ P2, /*Value*/ P2, /*Address*/ P2);602 // Replace both.603 TEST_REPLACE(/*Old*/ P2, /*New*/ P1, /*Value*/ P1, /*Address*/ P1);604 605 // Replace address only, value uses a DIArgList.606 // Value = {DIArgList(V1)}, Addr = P1.607 DbgAssign->setRawLocation(DIArgList::get(C, ValueAsMetadata::get(V1)));608 DbgAssign->setExpression(DIExpression::get(609 C, {dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_stack_value}));610 TEST_REPLACE(/*Old*/ P1, /*New*/ P2, /*Value*/ V1, /*Address*/ P2);611#undef TEST_REPLACE612}613 614TEST(AssignmentTrackingTest, Utils) {615 // Test the assignment tracking utils defined in DebugInfo.h namespace at {}.616 // This includes:617 // getAssignmentInsts618 // getAssignmentMarkers619 // RAUW620 // deleteAll621 //622 // The input IR includes two functions, fun1 and fun2. Both contain an alloca623 // with a DIAssignID tag. fun1's alloca is linked to two llvm.dbg.assign624 // intrinsics, one of which is for an inlined variable and appears before the625 // alloca.626 627 LLVMContext C;628 std::unique_ptr<Module> M = parseIR(C, R"(629 define dso_local void @fun1() !dbg !7 {630 entry:631 #dbg_assign(i32 undef, !10, !DIExpression(), !12, i32 undef, !DIExpression(), !13)632 %local = alloca i32, align 4, !DIAssignID !12633 #dbg_assign(i32 undef, !16, !DIExpression(), !12, i32 undef, !DIExpression(), !15)634 #dbg_assign(i32 undef, !16, !DIExpression(), !25, i32 undef, !DIExpression(), !15)635 #dbg_assign(i32 undef, !16, !DIExpression(), !25, i32 undef, !DIExpression(), !15)636 ret void, !dbg !15637 }638 639 define dso_local void @fun2() !dbg !17 {640 entry:641 %local = alloca i32, align 4, !DIAssignID !20642 #dbg_assign(i32 undef, !18, !DIExpression(), !20, i32 undef, !DIExpression(), !19)643 ret void, !dbg !19644 }645 646 define dso_local void @fun3() !dbg !21 {647 entry:648 %local = alloca i32, align 4, !DIAssignID !24649 #dbg_assign(i32 undef, !22, !DIExpression(), !24, i32* undef, !DIExpression(), !23)650 ret void651 }652 653 !llvm.dbg.cu = !{!0}654 !llvm.module.flags = !{!3, !4, !5}655 !llvm.ident = !{!6}656 657 !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)658 !1 = !DIFile(filename: "test.c", directory: "/")659 !2 = !{}660 !3 = !{i32 7, !"Dwarf Version", i32 4}661 !4 = !{i32 2, !"Debug Info Version", i32 3}662 !5 = !{i32 1, !"wchar_size", i32 4}663 !6 = !{!"clang version 14.0.0"}664 !7 = distinct !DISubprogram(name: "fun1", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)665 !8 = !DISubroutineType(types: !9)666 !9 = !{null}667 !10 = !DILocalVariable(name: "local3", scope: !14, file: !1, line: 2, type: !11)668 !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)669 !12 = distinct !DIAssignID()670 !13 = !DILocation(line: 5, column: 1, scope: !14, inlinedAt: !15)671 !14 = distinct !DISubprogram(name: "inline", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)672 !15 = !DILocation(line: 3, column: 1, scope: !7)673 !16 = !DILocalVariable(name: "local1", scope: !7, file: !1, line: 2, type: !11)674 !17 = distinct !DISubprogram(name: "fun2", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)675 !18 = !DILocalVariable(name: "local2", scope: !17, file: !1, line: 2, type: !11)676 !19 = !DILocation(line: 4, column: 1, scope: !17)677 !20 = distinct !DIAssignID()678 !21 = distinct !DISubprogram(name: "fun3", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)679 !22 = !DILocalVariable(name: "local4", scope: !21, file: !1, line: 2, type: !11)680 !23 = !DILocation(line: 4, column: 1, scope: !21)681 !24 = distinct !DIAssignID()682 !25 = distinct !DIAssignID()683 )");684 685 // Check the test IR isn't malformed.686 ASSERT_TRUE(M);687 688 Function &Fun1 = *M->getFunction("fun1");689 Instruction &Alloca = *Fun1.getEntryBlock().getFirstNonPHIOrDbg();690 691 // 1. Check the Instruction <-> Intrinsic mappings work in fun1.692 //693 // Check there are two llvm.dbg.assign intrinsics linked to Alloca.694 auto CheckFun1Mapping = [&Alloca]() {695 auto Markers = at::getDVRAssignmentMarkers(&Alloca);696 EXPECT_TRUE(std::distance(Markers.begin(), Markers.end()) == 2);697 // Check those two entries are distinct.698 DbgVariableRecord *First = *Markers.begin();699 DbgVariableRecord *Second = *std::next(Markers.begin());700 EXPECT_NE(First, Second);701 702 // Check that we can get back to Alloca from each llvm.dbg.assign.703 for (auto *DAI : Markers) {704 auto Insts = at::getAssignmentInsts(DAI);705 // Check there is exactly one instruction linked to each intrinsic. Use706 // ASSERT_TRUE because we're going to dereference the begin iterator.707 ASSERT_TRUE(std::distance(Insts.begin(), Insts.end()) == 1);708 EXPECT_FALSE(Insts.empty());709 // Check the linked instruction is Alloca.710 Instruction *LinkedInst = *Insts.begin();711 EXPECT_EQ(LinkedInst, &Alloca);712 }713 };714 CheckFun1Mapping();715 716 // 2. Check DIAssignID RAUW replaces attachments and uses.717 //718 DIAssignID *Old =719 cast_or_null<DIAssignID>(Alloca.getMetadata(LLVMContext::MD_DIAssignID));720 DIAssignID *New = DIAssignID::getDistinct(C);721 ASSERT_TRUE(Old && New && New != Old);722 at::RAUW(Old, New);723 // Check fun1's alloca and intrinsics have been updated and the mapping still724 // works.725 EXPECT_EQ(New, cast_or_null<DIAssignID>(726 Alloca.getMetadata(LLVMContext::MD_DIAssignID)));727 CheckFun1Mapping();728 729 // Check that fun2's alloca and intrinsic have not not been updated.730 Instruction &Fun2Alloca =731 *M->getFunction("fun2")->getEntryBlock().getFirstNonPHIOrDbg();732 DIAssignID *Fun2ID = cast_or_null<DIAssignID>(733 Fun2Alloca.getMetadata(LLVMContext::MD_DIAssignID));734 EXPECT_NE(New, Fun2ID);735 auto Fun2Markers = at::getDVRAssignmentMarkers(&Fun2Alloca);736 ASSERT_TRUE(std::distance(Fun2Markers.begin(), Fun2Markers.end()) == 1);737 auto Fun2Insts = at::getAssignmentInsts(*Fun2Markers.begin());738 ASSERT_TRUE(std::distance(Fun2Insts.begin(), Fun2Insts.end()) == 1);739 EXPECT_EQ(*Fun2Insts.begin(), &Fun2Alloca);740 741 // 3. Check that deleting dbg.assigns from a specific instruction works.742 Instruction &Fun3Alloca =743 *M->getFunction("fun3")->getEntryBlock().getFirstNonPHIOrDbg();744 auto Fun3Markers = at::getDVRAssignmentMarkers(&Fun3Alloca);745 ASSERT_TRUE(std::distance(Fun3Markers.begin(), Fun3Markers.end()) == 1);746 at::deleteAssignmentMarkers(&Fun3Alloca);747 Fun3Markers = at::getDVRAssignmentMarkers(&Fun3Alloca);748 EXPECT_EQ(Fun3Markers.empty(), true);749 750 // 4. Check that deleting works and applies only to the target function.751 at::deleteAll(&Fun1);752 // There should now only be the alloca and ret in fun1.753 EXPECT_EQ(Fun1.begin()->size(), 2u);754 // fun2's alloca should have the same DIAssignID and remain linked to its755 // llvm.dbg.assign.756 EXPECT_EQ(Fun2ID, cast_or_null<DIAssignID>(757 Fun2Alloca.getMetadata(LLVMContext::MD_DIAssignID)));758 EXPECT_FALSE(at::getDVRAssignmentMarkers(&Fun2Alloca).empty());759}760 761TEST(IRBuilder, GetSetInsertionPointWithEmptyBasicBlock) {762 LLVMContext C;763 std::unique_ptr<BasicBlock> BB(BasicBlock::Create(C, "start"));764 Module *M = new Module("module", C);765 IRBuilder<> Builder(BB.get());766 Function *DbgDeclare =767 Intrinsic::getOrInsertDeclaration(M, Intrinsic::dbg_declare);768 Value *DIV = MetadataAsValue::get(C, (Metadata *)nullptr);769 SmallVector<Value *, 3> Args = {DIV, DIV, DIV};770 Builder.CreateCall(DbgDeclare, Args);771 auto IP = BB->getFirstInsertionPt();772 Builder.SetInsertPoint(BB.get(), IP);773}774 775TEST(AssignmentTrackingTest, InstrMethods) {776 // Test the assignment tracking Instruction methods.777 // This includes:778 // Instruction::mergeDIAssignID779 780 LLVMContext C;781 std::unique_ptr<Module> M = parseIR(C, R"(782 define dso_local void @fun() #0 !dbg !8 {783 entry:784 %Local = alloca [2 x i32], align 4, !DIAssignID !12785 call void @llvm.dbg.assign(metadata i1 undef, metadata !13, metadata !DIExpression(), metadata !12, metadata [2 x i32]* %Local, metadata !DIExpression()), !dbg !18786 %arrayidx = getelementptr inbounds [2 x i32], [2 x i32]* %Local, i64 0, i64 0, !dbg !19787 store i32 5, i32* %arrayidx, align 4, !dbg !20, !DIAssignID !21788 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 !18789 %arrayidx1 = getelementptr inbounds [2 x i32], [2 x i32]* %Local, i64 0, i64 1, !dbg !22790 store i32 6, i32* %arrayidx1, align 4, !dbg !23, !DIAssignID !24791 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 !18792 ret void, !dbg !25793 }794 795 declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata) #1796 797 !llvm.dbg.cu = !{!0}798 !llvm.module.flags = !{!2, !3, !4, !5, !6}799 !llvm.ident = !{!7}800 801 !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)802 !1 = !DIFile(filename: "test.cpp", directory: "/")803 !2 = !{i32 7, !"Dwarf Version", i32 5}804 !3 = !{i32 2, !"Debug Info Version", i32 3}805 !4 = !{i32 1, !"wchar_size", i32 4}806 !5 = !{i32 7, !"uwtable", i32 1}807 !6 = !{i32 7, !"frame-pointer", i32 2}808 !7 = !{!"clang version 14.0.0"}809 !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)810 !9 = !DISubroutineType(types: !10)811 !10 = !{null}812 !11 = !{}813 !12 = distinct !DIAssignID()814 !13 = !DILocalVariable(name: "Local", scope: !8, file: !1, line: 2, type: !14)815 !14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !15, size: 64, elements: !16)816 !15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)817 !16 = !{!17}818 !17 = !DISubrange(count: 2)819 !18 = !DILocation(line: 0, scope: !8)820 !19 = !DILocation(line: 3, column: 3, scope: !8)821 !20 = !DILocation(line: 3, column: 12, scope: !8)822 !21 = distinct !DIAssignID()823 !22 = !DILocation(line: 4, column: 3, scope: !8)824 !23 = !DILocation(line: 4, column: 12, scope: !8)825 !24 = distinct !DIAssignID()826 !25 = !DILocation(line: 5, column: 1, scope: !8)827 )");828 829 // Check the test IR isn't malformed.830 ASSERT_TRUE(M);831 Function &Fun = *M->getFunction("fun");832 SmallVector<Instruction *> Stores;833 for (auto &BB : Fun) {834 for (auto &I : BB) {835 if (isa<StoreInst>(&I))836 Stores.push_back(&I);837 }838 }839 840 // The test requires (at least) 2 stores.841 ASSERT_TRUE(Stores.size() == 2);842 // Use SetVectors to check that the attachments and markers are unique843 // (another test requirement).844 SetVector<Metadata *> OrigIDs;845 SetVector<DbgVariableRecord *> Markers;846 for (const Instruction *SI : Stores) {847 Metadata *ID = SI->getMetadata(LLVMContext::MD_DIAssignID);848 ASSERT_TRUE(OrigIDs.insert(ID));849 ASSERT_TRUE(ID != nullptr);850 auto Range = at::getDVRAssignmentMarkers(SI);851 ASSERT_TRUE(std::distance(Range.begin(), Range.end()) == 1);852 ASSERT_TRUE(Markers.insert(*Range.begin()));853 }854 855 // Test 1 - mergeDIAssignID.856 //857 // Input store0->mergeDIAssignID(store1)858 // ----- -------------------------859 // store0 !x store0 !x860 // dbg.assign0 !x dbg.assign !x861 // store1 !y store1 !x862 // dbg.assign1 !y dbg.assign1 !x863 {864 Stores[0]->mergeDIAssignID(Stores[1]);865 // Check that the stores share the same ID.866 Metadata *NewID0 = Stores[0]->getMetadata(LLVMContext::MD_DIAssignID);867 Metadata *NewID1 = Stores[1]->getMetadata(LLVMContext::MD_DIAssignID);868 EXPECT_NE(NewID0, nullptr);869 EXPECT_EQ(NewID0, NewID1);870 EXPECT_EQ(Markers[0]->getAssignID(), NewID0);871 EXPECT_EQ(Markers[1]->getAssignID(), NewID0);872 }873 874 // Test 2 - mergeDIAssignID.875 //876 // Input store0->mergeDIAssignID(store1)877 // ----- -------------------------878 // store0 !x store0 !x879 // dbg.assign0 !x dbg.assign !x880 // store1 store1881 {882 Stores[1]->setMetadata(LLVMContext::MD_DIAssignID, nullptr);883 Stores[0]->mergeDIAssignID(Stores[1]);884 // Check that store1 doesn't get a new ID.885 Metadata *NewID0 = Stores[0]->getMetadata(LLVMContext::MD_DIAssignID);886 Metadata *NewID1 = Stores[1]->getMetadata(LLVMContext::MD_DIAssignID);887 EXPECT_NE(NewID0, nullptr);888 EXPECT_EQ(NewID1, nullptr);889 EXPECT_EQ(Markers[0]->getAssignID(), NewID0);890 }891 892 // Test 3 - mergeDIAssignID.893 //894 // Input store1->mergeDIAssignID(store0)895 // ----- -------------------------896 // store0 !x store0 !x897 // dbg.assign0 !x dbg.assign !x898 // store1 store1 !x899 {900 Stores[1]->setMetadata(LLVMContext::MD_DIAssignID, nullptr);901 Stores[1]->mergeDIAssignID(Stores[0]);902 // Check that the stores share the same ID (note store1 starts with none).903 Metadata *NewID0 = Stores[0]->getMetadata(LLVMContext::MD_DIAssignID);904 Metadata *NewID1 = Stores[1]->getMetadata(LLVMContext::MD_DIAssignID);905 EXPECT_NE(NewID0, nullptr);906 EXPECT_EQ(NewID0, NewID1);907 EXPECT_EQ(Markers[0]->getAssignID(), NewID0);908 }909 910 // Test 4 - mergeDIAssignID.911 //912 // Input store1->mergeDIAssignID(store0)913 // ----- -------------------------914 // store0 !x store0 !x915 // dbg.assign0 !x dbg.assign !x916 // store1 !x store1 !x917 {918 Stores[0]->mergeDIAssignID(Stores[1]);919 // Check that the stores share the same ID.920 Metadata *NewID0 = Stores[0]->getMetadata(LLVMContext::MD_DIAssignID);921 Metadata *NewID1 = Stores[1]->getMetadata(LLVMContext::MD_DIAssignID);922 EXPECT_NE(NewID0, nullptr);923 EXPECT_EQ(NewID0, NewID1);924 EXPECT_EQ(Markers[0]->getAssignID(), NewID0);925 }926 927 // Test 5 - dropUnknownNonDebugMetadata.928 //929 // Input store0->dropUnknownNonDebugMetadata()930 // ----- -------------------------931 // store0 !x store0 !x932 {933 Stores[0]->dropUnknownNonDebugMetadata();934 Metadata *NewID0 = Stores[0]->getMetadata(LLVMContext::MD_DIAssignID);935 EXPECT_NE(NewID0, nullptr);936 }937}938 939// Test some very straight-forward operations on DbgVariableRecords -- these are940// dbg.values that have been converted to a non-instruction format.941TEST(MetadataTest, ConvertDbgToDbgVariableRecord) {942 LLVMContext C;943 std::unique_ptr<Module> M = parseIR(C, R"(944 define i16 @f(i16 %a) !dbg !6 {945 call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11946 %b = add i16 %a, 1, !dbg !11947 call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11948 ret i16 0, !dbg !11949 950 exit:951 %c = add i16 %b, 1, !dbg !11952 ret i16 0, !dbg !11953 }954 declare void @llvm.dbg.value(metadata, metadata, metadata) #0955 attributes #0 = { nounwind readnone speculatable willreturn }956 957 !llvm.dbg.cu = !{!0}958 !llvm.module.flags = !{!5}959 960 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)961 !1 = !DIFile(filename: "t.ll", directory: "/")962 !2 = !{}963 !5 = !{i32 2, !"Debug Info Version", i32 3}964 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)965 !7 = !DISubroutineType(types: !2)966 !8 = !{!9}967 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)968 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)969 !11 = !DILocation(line: 1, column: 1, scope: !6)970)");971 972 // The IR above will be autoupgraded to debug records: but this test is about973 // the conversion routines, so convert it back. This test will have value974 // going forwards for the purpose of testing the conversion routine, which975 // some compatibility tools (DXIL?) wish to use.976 M->convertFromNewDbgValues();977 978 // Find the first dbg.value,979 Instruction &I = *M->getFunction("f")->getEntryBlock().getFirstNonPHIIt();980 const DILocalVariable *Var = nullptr;981 const DIExpression *Expr = nullptr;982 const DILocation *Loc = nullptr;983 const Metadata *MLoc = nullptr;984 DbgVariableRecord *DVR1 = nullptr;985 {986 DbgValueInst *DPI = dyn_cast<DbgValueInst>(&I);987 ASSERT_TRUE(DPI);988 Var = DPI->getVariable();989 Expr = DPI->getExpression();990 Loc = DPI->getDebugLoc().get();991 MLoc = DPI->getRawLocation();992 993 // Test the creation of a DbgVariableRecord and it's conversion back to a994 // dbg.value.995 DVR1 = new DbgVariableRecord(DPI);996 EXPECT_EQ(DVR1->getVariable(), Var);997 EXPECT_EQ(DVR1->getExpression(), Expr);998 EXPECT_EQ(DVR1->getDebugLoc().get(), Loc);999 EXPECT_EQ(DVR1->getRawLocation(), MLoc);1000 1001 // Erase dbg.value,1002 DPI->eraseFromParent();1003 // Re-create from DVR1, inserting at front.1004 DVR1->createDebugIntrinsic(&*M,1005 &M->getFunction("f")->getEntryBlock().front());1006 1007 Instruction *NewDPI = &M->getFunction("f")->getEntryBlock().front();1008 DbgValueInst *DPI2 = dyn_cast<DbgValueInst>(NewDPI);1009 ASSERT_TRUE(DPI2);1010 EXPECT_EQ(DPI2->getVariable(), Var);1011 EXPECT_EQ(DPI2->getExpression(), Expr);1012 EXPECT_EQ(DPI2->getDebugLoc().get(), Loc);1013 EXPECT_EQ(DPI2->getRawLocation(), MLoc);1014 }1015 1016 // Fetch the second dbg.value, convert it to a DbgVariableRecord,1017 BasicBlock::iterator It = M->getFunction("f")->getEntryBlock().begin();1018 It = std::next(std::next(It));1019 DbgValueInst *DPI3 = dyn_cast<DbgValueInst>(It);1020 ASSERT_TRUE(DPI3);1021 DbgVariableRecord *DVR2 = new DbgVariableRecord(DPI3);1022 1023 // These dbg.values are supposed to refer to different values.1024 EXPECT_NE(DVR1->getRawLocation(), DVR2->getRawLocation());1025 1026 // Try manipulating DbgVariableRecords and markers in the exit block.1027 BasicBlock *ExitBlock = &*std::next(M->getFunction("f")->getEntryBlock().getIterator());1028 Instruction *FirstInst = &ExitBlock->front();1029 Instruction *RetInst = &*std::next(FirstInst->getIterator());1030 1031 // Set-up DbgMarkers in this block.1032 ExitBlock->createMarker(FirstInst);1033 ExitBlock->createMarker(RetInst);1034 1035 // Insert DbgRecords into markers, order should come out DVR2, DVR1.1036 FirstInst->DebugMarker->insertDbgRecord(DVR1, false);1037 FirstInst->DebugMarker->insertDbgRecord(DVR2, true);1038 unsigned int ItCount = 0;1039 for (DbgRecord &Item : FirstInst->DebugMarker->getDbgRecordRange()) {1040 EXPECT_TRUE((&Item == DVR2 && ItCount == 0) ||1041 (&Item == DVR1 && ItCount == 1));1042 EXPECT_EQ(Item.getMarker(), FirstInst->DebugMarker);1043 ++ItCount;1044 }1045 1046 // Clone them onto the second marker -- should allocate new DVRs.1047 RetInst->DebugMarker->cloneDebugInfoFrom(FirstInst->DebugMarker, std::nullopt,1048 false);1049 EXPECT_EQ(RetInst->DebugMarker->StoredDbgRecords.size(), 2u);1050 ItCount = 0;1051 // Check these things store the same information; but that they're not the same1052 // objects.1053 for (DbgVariableRecord &Item :1054 filterDbgVars(RetInst->DebugMarker->getDbgRecordRange())) {1055 EXPECT_TRUE(1056 (Item.getRawLocation() == DVR2->getRawLocation() && ItCount == 0) ||1057 (Item.getRawLocation() == DVR1->getRawLocation() && ItCount == 1));1058 1059 EXPECT_EQ(Item.getMarker(), RetInst->DebugMarker);1060 EXPECT_NE(&Item, DVR1);1061 EXPECT_NE(&Item, DVR2);1062 ++ItCount;1063 }1064 1065 RetInst->DebugMarker->dropDbgRecords();1066 EXPECT_EQ(RetInst->DebugMarker->StoredDbgRecords.size(), 0u);1067 1068 // Try cloning one single DbgVariableRecord.1069 auto DIIt = std::next(FirstInst->DebugMarker->getDbgRecordRange().begin());1070 RetInst->DebugMarker->cloneDebugInfoFrom(FirstInst->DebugMarker, DIIt, false);1071 EXPECT_EQ(RetInst->DebugMarker->StoredDbgRecords.size(), 1u);1072 // The second DbgVariableRecord should have been cloned; it should have the1073 // same values as DVR1.1074 EXPECT_EQ(1075 cast<DbgVariableRecord>(RetInst->DebugMarker->StoredDbgRecords.begin())1076 ->getRawLocation(),1077 DVR1->getRawLocation());1078 // We should be able to drop individual DbgRecords.1079 RetInst->DebugMarker->dropOneDbgRecord(1080 &*RetInst->DebugMarker->StoredDbgRecords.begin());1081 1082 // "Aborb" a DbgMarker: this means pretend that the instruction it's attached1083 // to is disappearing so it needs to be transferred into "this" marker.1084 RetInst->DebugMarker->absorbDebugValues(*FirstInst->DebugMarker, true);1085 EXPECT_EQ(RetInst->DebugMarker->StoredDbgRecords.size(), 2u);1086 // Should be the DVR1 and DVR2 objects.1087 ItCount = 0;1088 for (DbgRecord &Item : RetInst->DebugMarker->getDbgRecordRange()) {1089 EXPECT_TRUE((&Item == DVR2 && ItCount == 0) ||1090 (&Item == DVR1 && ItCount == 1));1091 EXPECT_EQ(Item.getMarker(), RetInst->DebugMarker);1092 ++ItCount;1093 }1094 1095 // Finally -- there are two DbgVariableRecords left over. If we remove1096 // evrything in the basic block, then they should sink down into the1097 // "TrailingDbgRecords" container for dangling debug-info. Future facilities1098 // will restore them back when a terminator is inserted.1099 FirstInst->DebugMarker->removeMarker();1100 FirstInst->eraseFromParent();1101 RetInst->DebugMarker->removeMarker();1102 RetInst->eraseFromParent();1103 1104 DbgMarker *EndMarker = ExitBlock->getTrailingDbgRecords();1105 ASSERT_NE(EndMarker, nullptr);1106 EXPECT_EQ(EndMarker->StoredDbgRecords.size(), 2u);1107 // Test again that it's those two DbgVariableRecords, DVR1 and DVR2.1108 ItCount = 0;1109 for (DbgRecord &Item : EndMarker->getDbgRecordRange()) {1110 EXPECT_TRUE((&Item == DVR2 && ItCount == 0) ||1111 (&Item == DVR1 && ItCount == 1));1112 EXPECT_EQ(Item.getMarker(), EndMarker);1113 ++ItCount;1114 }1115 1116 // Cleanup the trailing DbgVariableRecord records and marker.1117 EndMarker->eraseFromParent();1118 1119 // The record of those trailing DbgVariableRecords would dangle and cause an1120 // assertion failure if it lived until the end of the LLVMContext.1121 ExitBlock->deleteTrailingDbgRecords();1122}1123 1124TEST(MetadataTest, DbgVariableRecordConversionRoutines) {1125 LLVMContext C;1126 1127 std::unique_ptr<Module> M = parseIR(C, R"(1128 define i16 @f(i16 %a) !dbg !6 {1129 call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !111130 %b = add i16 %a, 1, !dbg !111131 call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !111132 ret i16 0, !dbg !111133 1134 exit:1135 %c = add i16 %b, 1, !dbg !111136 ret i16 0, !dbg !111137 }1138 declare void @llvm.dbg.value(metadata, metadata, metadata) #01139 attributes #0 = { nounwind readnone speculatable willreturn }1140 1141 !llvm.dbg.cu = !{!0}1142 !llvm.module.flags = !{!5}1143 1144 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)1145 !1 = !DIFile(filename: "t.ll", directory: "/")1146 !2 = !{}1147 !5 = !{i32 2, !"Debug Info Version", i32 3}1148 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)1149 !7 = !DISubroutineType(types: !2)1150 !8 = !{!9}1151 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)1152 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)1153 !11 = !DILocation(line: 1, column: 1, scope: !6)1154)");1155 1156 // This test exists to check we can convert back and forth between old and new1157 // debug info formats (dbg.value intrinsics versus #dbg_value records).1158 // We're ripping out support for debug intrinsics, but the conversions will1159 // live on in bitcode autoupgrade and possibly DXIL autodowngrade. Thus, this1160 // test is still valuable. Begin by starting in the intrinsic format:1161 M->convertFromNewDbgValues();1162 1163 Function *F = M->getFunction("f");1164 BasicBlock *BB1 = &F->getEntryBlock();1165 // First instruction should be a dbg.value.1166 EXPECT_TRUE(isa<DbgValueInst>(BB1->front()));1167 // Validating the block for DbgVariableRecords / DbgMarkers shouldn't fail --1168 // there's no data stored right now.1169 bool BrokenDebugInfo = false;1170 bool Error = verifyModule(*M, &errs(), &BrokenDebugInfo);1171 EXPECT_FALSE(Error);1172 EXPECT_FALSE(BrokenDebugInfo);1173 1174 // Now convert.1175 M->convertToNewDbgValues();1176 1177 // There should now be no dbg.value instructions!1178 // Ensure the first instruction exists, the test all of them.1179 EXPECT_FALSE(isa<DbgValueInst>(BB1->front()));1180 for (auto &BB : *F)1181 for (auto &I : BB)1182 EXPECT_FALSE(isa<DbgValueInst>(I));1183 1184 // There should be a DbgMarker on each of the two instructions in the entry1185 // block, each containing one DbgVariableRecord.1186 EXPECT_EQ(BB1->size(), 2u);1187 Instruction *FirstInst = &BB1->front();1188 Instruction *SecondInst = FirstInst->getNextNode();1189 ASSERT_TRUE(FirstInst->DebugMarker);1190 ASSERT_TRUE(SecondInst->DebugMarker);1191 EXPECT_NE(FirstInst->DebugMarker, SecondInst->DebugMarker);1192 EXPECT_EQ(FirstInst, FirstInst->DebugMarker->MarkedInstr);1193 EXPECT_EQ(SecondInst, SecondInst->DebugMarker->MarkedInstr);1194 1195 EXPECT_EQ(FirstInst->DebugMarker->StoredDbgRecords.size(), 1u);1196 DbgVariableRecord *DVR1 = cast<DbgVariableRecord>(1197 &*FirstInst->DebugMarker->getDbgRecordRange().begin());1198 EXPECT_EQ(DVR1->getMarker(), FirstInst->DebugMarker);1199 // Should point at %a, an argument.1200 EXPECT_TRUE(isa<Argument>(DVR1->getVariableLocationOp(0)));1201 1202 EXPECT_EQ(SecondInst->DebugMarker->StoredDbgRecords.size(), 1u);1203 DbgVariableRecord *DVR2 = cast<DbgVariableRecord>(1204 &*SecondInst->DebugMarker->getDbgRecordRange().begin());1205 EXPECT_EQ(DVR2->getMarker(), SecondInst->DebugMarker);1206 // Should point at FirstInst.1207 EXPECT_EQ(DVR2->getVariableLocationOp(0), FirstInst);1208 1209 // There should be no DbgVariableRecords / DbgMarkers in the second block, but1210 // it should be marked as being in the new format.1211 BasicBlock *BB2 = BB1->getNextNode();1212 for (auto &Inst : *BB2)1213 // Either there should be no marker, or it should be empty.1214 EXPECT_TRUE(!Inst.DebugMarker ||1215 Inst.DebugMarker->StoredDbgRecords.empty());1216 1217 // Validating the first block should continue to not be a problem,1218 Error = verifyModule(*M, &errs(), &BrokenDebugInfo);1219 EXPECT_FALSE(Error);1220 EXPECT_FALSE(BrokenDebugInfo);1221 // But if we were to break something, it should be able to fire. Don't attempt1222 // to comprehensively test the validator, it's a smoke-test rather than a1223 // "proper" verification pass.1224 DVR1->setMarker(nullptr);1225 // A marker pointing the wrong way should be an error.1226 Error = verifyModule(*M, &errs(), &BrokenDebugInfo);1227 EXPECT_FALSE(Error);1228 EXPECT_TRUE(BrokenDebugInfo);1229 DVR1->setMarker(FirstInst->DebugMarker);1230 1231 DILocalVariable *DLV1 = DVR1->getVariable();1232 DIExpression *Expr1 = DVR1->getExpression();1233 DILocalVariable *DLV2 = DVR2->getVariable();1234 DIExpression *Expr2 = DVR2->getExpression();1235 1236 // Convert everything back to the "old" format and ensure it's right.1237 M->convertFromNewDbgValues();1238 1239 EXPECT_EQ(BB1->size(), 4u);1240 ASSERT_TRUE(isa<DbgValueInst>(BB1->front()));1241 DbgValueInst *DVI1 = cast<DbgValueInst>(&BB1->front());1242 // These dbg.values should still point at the same places.1243 EXPECT_TRUE(isa<Argument>(DVI1->getVariableLocationOp(0)));1244 DbgValueInst *DVI2 = cast<DbgValueInst>(DVI1->getNextNode()->getNextNode());1245 EXPECT_EQ(DVI2->getVariableLocationOp(0), FirstInst);1246 1247 // Check a few fields too,1248 EXPECT_EQ(DVI1->getVariable(), DLV1);1249 EXPECT_EQ(DVI1->getExpression(), Expr1);1250 EXPECT_EQ(DVI2->getVariable(), DLV2);1251 EXPECT_EQ(DVI2->getExpression(), Expr2);1252}1253 1254TEST(MetadataTest, InlinedAtMethodsWithMultipleLevels) {1255 LLVMContext C;1256 1257 // Create IR with 3 levels of inlining:1258 // main() calls inline1() which calls inline2() which calls inline3()1259 // We'll test from the perspective of code in inline3()1260 std::unique_ptr<Module> M = parseIR(C, R"(1261 define void @main() !dbg !10 {1262 ret void, !dbg !201263 }1264 1265 !llvm.dbg.cu = !{!0}1266 !llvm.module.flags = !{!2}1267 1268 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1)1269 !1 = !DIFile(filename: "test.c", directory: "/test")1270 !2 = !{i32 2, !"Debug Info Version", i32 3}1271 1272 ; Subprograms for each function in the call chain1273 !10 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 100, unit: !0)1274 !11 = distinct !DISubprogram(name: "inline1", scope: !1, file: !1, line: 200, unit: !0)1275 !12 = distinct !DISubprogram(name: "inline2", scope: !1, file: !1, line: 300, unit: !0)1276 !13 = distinct !DISubprogram(name: "inline3", scope: !1, file: !1, line: 400, unit: !0)1277 1278 ; Location in inline3 (line 401), inlined at location !211279 !20 = !DILocation(line: 401, column: 5, scope: !13, inlinedAt: !21)1280 1281 ; Location in inline2 (line 301) where inline3 was called, inlined at !221282 !21 = !DILocation(line: 301, column: 10, scope: !12, inlinedAt: !22)1283 1284 ; Location in inline1 (line 201) where inline2 was called, inlined at !231285 !22 = !DILocation(line: 201, column: 15, scope: !11, inlinedAt: !23)1286 1287 ; Location in main (line 101) where inline1 was called (no more inlinedAt)1288 !23 = !DILocation(line: 101, column: 3, scope: !10)1289 )");1290 1291 ASSERT_TRUE(M);1292 1293 Function *MainFunc = M->getFunction("main");1294 ASSERT_TRUE(MainFunc);1295 Instruction &RetInst = MainFunc->getEntryBlock().front();1296 1297 // Use getDebugLoc() to get the location from the ret instruction.1298 const DILocation *InnermostLoc = RetInst.getDebugLoc().get();1299 ASSERT_TRUE(InnermostLoc);1300 1301 // Test getScope() - should return the immediate scope (inline3).1302 DILocalScope *ImmediateScope = InnermostLoc->getScope();1303 ASSERT_TRUE(ImmediateScope);1304 EXPECT_TRUE(isa<DISubprogram>(ImmediateScope));1305 EXPECT_EQ(cast<DISubprogram>(ImmediateScope)->getName(), "inline3");1306 1307 // Test getInlinedAt() - should return the next level in the inlining chain.1308 const DILocation *NextLevel = InnermostLoc->getInlinedAt();1309 ASSERT_TRUE(NextLevel);1310 EXPECT_EQ(NextLevel->getLine(), 301u);1311 EXPECT_EQ(cast<DISubprogram>(NextLevel->getScope())->getName(), "inline2");1312 1313 // Test getInlinedAtLocation() - should return the outermost location.1314 const DILocation *OutermostLoc = InnermostLoc->getInlinedAtLocation();1315 ASSERT_TRUE(OutermostLoc);1316 EXPECT_EQ(OutermostLoc->getLine(), 101u);1317 EXPECT_EQ(OutermostLoc->getColumn(), 3u);1318 EXPECT_EQ(OutermostLoc->getInlinedAt(), nullptr);1319 EXPECT_EQ(cast<DISubprogram>(OutermostLoc->getScope())->getName(), "main");1320 1321 // Test getInlinedAtScope() - should return the scope of the outermost1322 // location.1323 DILocalScope *InlinedAtScope = InnermostLoc->getInlinedAtScope();1324 ASSERT_TRUE(InlinedAtScope);1325 EXPECT_TRUE(isa<DISubprogram>(InlinedAtScope));1326 EXPECT_EQ(cast<DISubprogram>(InlinedAtScope)->getName(), "main");1327 EXPECT_EQ(InlinedAtScope, OutermostLoc->getScope());1328}1329 1330// Test that the hashing function for DISubprograms representing methods produce1331// the same result after replacing their scope (the type containing the1332// subprogram) from a temporary DIType with the permanent one.1333TEST(DIBuilder, HashingDISubprogram) {1334 LLVMContext Ctx;1335 std::unique_ptr<Module> M = std::make_unique<Module>("MyModule", Ctx);1336 DIBuilder DIB(*M);1337 1338 DIFile *F = DIB.createFile("main.c", "/");1339 DICompileUnit *CU = DIB.createCompileUnit(1340 DISourceLanguageName(dwarf::DW_LANG_C), F, "Test", false, "", 0);1341 1342 llvm::TempDIType ForwardDeclaredType =1343 llvm::TempDIType(DIB.createReplaceableCompositeType(1344 llvm::dwarf::DW_TAG_structure_type, "MyType", CU, F, 0, 0, 8, 8, {},1345 "UniqueIdentifier"));1346 1347 // The hashing function is different for declarations and definitions, so1348 // create one of each.1349 DISubprogram *Declaration =1350 DIB.createMethod(ForwardDeclaredType.get(), "MethodName", "LinkageName",1351 F, 0, DIB.createSubroutineType({}));1352 1353 DISubprogram *Definition = DIB.createFunction(1354 ForwardDeclaredType.get(), "MethodName", "LinkageName", F, 0,1355 DIB.createSubroutineType({}), 0, DINode::FlagZero,1356 llvm::DISubprogram::SPFlagDefinition, nullptr, Declaration);1357 1358 // Produce the hash with the temporary scope.1359 unsigned HashDeclaration =1360 MDNodeKeyImpl<DISubprogram>(Declaration).getHashValue();1361 unsigned HashDefinition =1362 MDNodeKeyImpl<DISubprogram>(Definition).getHashValue();1363 1364 // Instantiate the real scope and replace the temporary one with it.1365 DICompositeType *Type = DIB.createStructType(CU, "MyType", F, 0, 8, 8, {}, {},1366 {}, 0, {}, "UniqueIdentifier");1367 DIB.replaceTemporary(std::move(ForwardDeclaredType), Type);1368 1369 // Now make sure the hashing is consistent.1370 unsigned HashDeclarationAfter =1371 MDNodeKeyImpl<DISubprogram>(Declaration).getHashValue();1372 unsigned HashDefinitionAfter =1373 MDNodeKeyImpl<DISubprogram>(Definition).getHashValue();1374 1375 EXPECT_EQ(HashDeclaration, HashDeclarationAfter);1376 EXPECT_EQ(HashDefinition, HashDefinitionAfter);1377}1378 1379TEST(DIBuilder, CompositeTypes) {1380 LLVMContext Ctx;1381 std::unique_ptr<Module> M = std::make_unique<Module>("MyModule", Ctx);1382 DIBuilder DIB(*M);1383 1384 DIFile *F = DIB.createFile("main.c", "/");1385 DICompileUnit *CU = DIB.createCompileUnit(1386 DISourceLanguageName(dwarf::DW_LANG_C), F, "Test", false, "", 0);1387 1388 DICompositeType *Class =1389 DIB.createClassType(CU, "MyClass", F, 0, 8, 8, 0, {}, nullptr, {}, 0,1390 nullptr, nullptr, "ClassUniqueIdentifier");1391 EXPECT_EQ(Class->getTag(), dwarf::DW_TAG_class_type);1392 1393 DICompositeType *Struct = DIB.createStructType(1394 CU, "MyStruct", F, 0, 8, 8, {}, {}, {}, 0, {}, "StructUniqueIdentifier");1395 EXPECT_EQ(Struct->getTag(), dwarf::DW_TAG_structure_type);1396 1397 DICompositeType *Union = DIB.createUnionType(CU, "MyUnion", F, 0, 8, 8, {},1398 {}, 0, "UnionUniqueIdentifier");1399 EXPECT_EQ(Union->getTag(), dwarf::DW_TAG_union_type);1400 1401 DICompositeType *Array = DIB.createArrayType(8, 8, nullptr, {});1402 EXPECT_EQ(Array->getTag(), dwarf::DW_TAG_array_type);1403 1404 StringRef ArrayNameExp = "AnArray";1405 DICompositeType *NamedArray =1406 DIB.createArrayType(nullptr, ArrayNameExp, nullptr, 0, 8, 8, nullptr, {});1407 EXPECT_EQ(NamedArray->getTag(), dwarf::DW_TAG_array_type);1408 EXPECT_EQ(NamedArray->getName(), ArrayNameExp);1409 1410 DICompositeType *Vector = DIB.createVectorType(8, 8, nullptr, {});1411 EXPECT_EQ(Vector->getTag(), dwarf::DW_TAG_array_type);1412 1413 DICompositeType *Enum = DIB.createEnumerationType(1414 CU, "MyEnum", F, 0, 8, 8, {}, nullptr, 0, "EnumUniqueIdentifier");1415 EXPECT_EQ(Enum->getTag(), dwarf::DW_TAG_enumeration_type);1416}1417 1418TEST(DIBuilder, DynamicOffsetAndSize) {1419 LLVMContext Ctx;1420 auto M = std::make_unique<Module>("MyModule", Ctx);1421 DIBuilder DIB(*M);1422 DIScope *Scope = DISubprogram::getDistinct(1423 Ctx, nullptr, "", "", nullptr, 0, nullptr, 0, nullptr, 0, 0,1424 DINode::FlagZero, DISubprogram::SPFlagZero, nullptr);1425 DIFile *F = DIB.createFile("main.adb", "/");1426 1427 DIVariable *Len = DIB.createAutoVariable(Scope, "length", F, 0, nullptr,1428 false, DINode::FlagZero, 0);1429 1430 DICompositeType *Struct = DIB.createStructType(1431 Scope, "some_record", F, 18, Len, 8, DINode::FlagZero, nullptr, {});1432 EXPECT_EQ(Struct->getTag(), dwarf::DW_TAG_structure_type);1433 1434 SmallVector<uint64_t, 4> ops;1435 ops.push_back(llvm::dwarf::DW_OP_push_object_address);1436 DIExpression::appendOffset(ops, 3);1437 ops.push_back(llvm::dwarf::DW_OP_deref);1438 DIExpression *Expr = DIB.createExpression(ops);1439 1440 DIDerivedType *Field = DIB.createMemberType(Scope, "field", F, 23, Len, 0,1441 Expr, DINode::FlagZero, Struct);1442 1443 EXPECT_EQ(Field->getRawOffsetInBits(), Expr);1444 EXPECT_EQ(Field->getRawSizeInBits(), Len);1445}1446 1447} // end namespace1448