2014-10-03 22:01:09 +02:00
|
|
|
//===- llvm/unittest/IR/DebugInfo.cpp - DebugInfo tests -------------------===//
|
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2014-10-03 22:01:09 +02:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2020-04-30 22:22:22 +02:00
|
|
|
#include "llvm/IR/DebugInfo.h"
|
2020-10-28 20:26:44 +01:00
|
|
|
#include "llvm/IR/DIBuilder.h"
|
2020-04-30 22:22:22 +02:00
|
|
|
#include "llvm/AsmParser/Parser.h"
|
2015-04-07 03:21:40 +02:00
|
|
|
#include "llvm/IR/DebugInfoMetadata.h"
|
[Instruction] Set metadata uses to undef on deletion
Summary:
Replace any extant metadata uses of a dying instruction with undef to
preserve debug info accuracy. Some alternatives include:
- Treat Instruction like any other Value, and point its extant metadata
uses to an empty ValueAsMetadata node. This makes extant dbg.value uses
trivially dead (i.e. fair game for deletion in many passes), leading to
stale dbg.values being in effect for too long.
- Call salvageDebugInfoOrMarkUndef. Not needed to make instruction removal
correct. OTOH results in wasted work in some common cases (e.g. when all
instructions in a BasicBlock are deleted).
This came up while discussing some basic cases in
https://reviews.llvm.org/D80052.
Reviewers: jmorse, TWeaver, aprantl, dexonsmith, jdoerfert
Subscribers: jholewinski, qcolombet, hiraditya, jfb, sstefan1, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D80264
2020-05-20 03:03:22 +02:00
|
|
|
#include "llvm/IR/IntrinsicInst.h"
|
2020-04-30 22:22:22 +02:00
|
|
|
#include "llvm/IR/LLVMContext.h"
|
|
|
|
#include "llvm/IR/Module.h"
|
|
|
|
#include "llvm/IR/Verifier.h"
|
|
|
|
#include "llvm/Support/SourceMgr.h"
|
[Instruction] Set metadata uses to undef on deletion
Summary:
Replace any extant metadata uses of a dying instruction with undef to
preserve debug info accuracy. Some alternatives include:
- Treat Instruction like any other Value, and point its extant metadata
uses to an empty ValueAsMetadata node. This makes extant dbg.value uses
trivially dead (i.e. fair game for deletion in many passes), leading to
stale dbg.values being in effect for too long.
- Call salvageDebugInfoOrMarkUndef. Not needed to make instruction removal
correct. OTOH results in wasted work in some common cases (e.g. when all
instructions in a BasicBlock are deleted).
This came up while discussing some basic cases in
https://reviews.llvm.org/D80052.
Reviewers: jmorse, TWeaver, aprantl, dexonsmith, jdoerfert
Subscribers: jholewinski, qcolombet, hiraditya, jfb, sstefan1, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D80264
2020-05-20 03:03:22 +02:00
|
|
|
#include "llvm/Transforms/Utils/Local.h"
|
2014-10-03 22:01:09 +02:00
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
2020-04-30 22:22:22 +02:00
|
|
|
static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
|
|
|
|
SMDiagnostic Err;
|
|
|
|
std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
|
|
|
|
if (!Mod)
|
|
|
|
Err.print("DebugInfoTest", errs());
|
|
|
|
return Mod;
|
|
|
|
}
|
|
|
|
|
2014-10-03 22:01:09 +02:00
|
|
|
namespace {
|
|
|
|
|
2015-04-29 18:38:44 +02:00
|
|
|
TEST(DINodeTest, getFlag) {
|
2015-02-21 01:43:09 +01:00
|
|
|
// Some valid flags.
|
2015-04-29 18:38:44 +02:00
|
|
|
EXPECT_EQ(DINode::FlagPublic, DINode::getFlag("DIFlagPublic"));
|
|
|
|
EXPECT_EQ(DINode::FlagProtected, DINode::getFlag("DIFlagProtected"));
|
|
|
|
EXPECT_EQ(DINode::FlagPrivate, DINode::getFlag("DIFlagPrivate"));
|
|
|
|
EXPECT_EQ(DINode::FlagVector, DINode::getFlag("DIFlagVector"));
|
|
|
|
EXPECT_EQ(DINode::FlagRValueReference,
|
|
|
|
DINode::getFlag("DIFlagRValueReference"));
|
2015-02-21 01:43:09 +01:00
|
|
|
|
|
|
|
// FlagAccessibility shouldn't work.
|
2015-04-29 18:38:44 +02:00
|
|
|
EXPECT_EQ(0u, DINode::getFlag("DIFlagAccessibility"));
|
2015-02-21 01:43:09 +01:00
|
|
|
|
|
|
|
// Some other invalid strings.
|
2015-04-29 18:38:44 +02:00
|
|
|
EXPECT_EQ(0u, DINode::getFlag("FlagVector"));
|
|
|
|
EXPECT_EQ(0u, DINode::getFlag("Vector"));
|
|
|
|
EXPECT_EQ(0u, DINode::getFlag("other things"));
|
|
|
|
EXPECT_EQ(0u, DINode::getFlag("DIFlagOther"));
|
2015-02-21 01:43:09 +01:00
|
|
|
}
|
|
|
|
|
2015-04-29 18:38:44 +02:00
|
|
|
TEST(DINodeTest, getFlagString) {
|
2015-02-21 01:43:09 +01:00
|
|
|
// Some valid flags.
|
|
|
|
EXPECT_EQ(StringRef("DIFlagPublic"),
|
2015-04-29 18:38:44 +02:00
|
|
|
DINode::getFlagString(DINode::FlagPublic));
|
2015-02-21 01:43:09 +01:00
|
|
|
EXPECT_EQ(StringRef("DIFlagProtected"),
|
2015-04-29 18:38:44 +02:00
|
|
|
DINode::getFlagString(DINode::FlagProtected));
|
2015-02-21 01:43:09 +01:00
|
|
|
EXPECT_EQ(StringRef("DIFlagPrivate"),
|
2015-04-29 18:38:44 +02:00
|
|
|
DINode::getFlagString(DINode::FlagPrivate));
|
2015-02-21 01:43:09 +01:00
|
|
|
EXPECT_EQ(StringRef("DIFlagVector"),
|
2015-04-29 18:38:44 +02:00
|
|
|
DINode::getFlagString(DINode::FlagVector));
|
2015-02-21 01:43:09 +01:00
|
|
|
EXPECT_EQ(StringRef("DIFlagRValueReference"),
|
2015-04-29 18:38:44 +02:00
|
|
|
DINode::getFlagString(DINode::FlagRValueReference));
|
2015-02-21 01:43:09 +01:00
|
|
|
|
|
|
|
// FlagAccessibility actually equals FlagPublic.
|
|
|
|
EXPECT_EQ(StringRef("DIFlagPublic"),
|
2015-04-29 18:38:44 +02:00
|
|
|
DINode::getFlagString(DINode::FlagAccessibility));
|
2015-02-21 01:43:09 +01:00
|
|
|
|
|
|
|
// Some other invalid flags.
|
2015-04-29 18:38:44 +02:00
|
|
|
EXPECT_EQ(StringRef(),
|
|
|
|
DINode::getFlagString(DINode::FlagPublic | DINode::FlagVector));
|
|
|
|
EXPECT_EQ(StringRef(), DINode::getFlagString(DINode::FlagFwdDecl |
|
|
|
|
DINode::FlagArtificial));
|
2016-09-06 12:46:28 +02:00
|
|
|
EXPECT_EQ(StringRef(),
|
|
|
|
DINode::getFlagString(static_cast<DINode::DIFlags>(0xffff)));
|
2015-02-21 01:43:09 +01:00
|
|
|
}
|
|
|
|
|
2015-04-29 18:38:44 +02:00
|
|
|
TEST(DINodeTest, splitFlags) {
|
2015-04-07 03:21:40 +02:00
|
|
|
// Some valid flags.
|
2015-02-21 01:45:26 +01:00
|
|
|
#define CHECK_SPLIT(FLAGS, VECTOR, REMAINDER) \
|
|
|
|
{ \
|
2016-09-06 12:46:28 +02:00
|
|
|
SmallVector<DINode::DIFlags, 8> V; \
|
2015-04-29 18:38:44 +02:00
|
|
|
EXPECT_EQ(REMAINDER, DINode::splitFlags(FLAGS, V)); \
|
2015-04-07 03:21:40 +02:00
|
|
|
EXPECT_TRUE(makeArrayRef(V).equals(VECTOR)); \
|
2015-02-21 01:45:26 +01:00
|
|
|
}
|
2016-09-06 12:46:28 +02:00
|
|
|
CHECK_SPLIT(DINode::FlagPublic, {DINode::FlagPublic}, DINode::FlagZero);
|
|
|
|
CHECK_SPLIT(DINode::FlagProtected, {DINode::FlagProtected}, DINode::FlagZero);
|
|
|
|
CHECK_SPLIT(DINode::FlagPrivate, {DINode::FlagPrivate}, DINode::FlagZero);
|
|
|
|
CHECK_SPLIT(DINode::FlagVector, {DINode::FlagVector}, DINode::FlagZero);
|
2016-09-06 19:03:02 +02:00
|
|
|
CHECK_SPLIT(DINode::FlagRValueReference, {DINode::FlagRValueReference},
|
|
|
|
DINode::FlagZero);
|
2016-09-06 12:46:28 +02:00
|
|
|
DINode::DIFlags Flags[] = {DINode::FlagFwdDecl, DINode::FlagVector};
|
2016-09-06 19:03:02 +02:00
|
|
|
CHECK_SPLIT(DINode::FlagFwdDecl | DINode::FlagVector, Flags,
|
|
|
|
DINode::FlagZero);
|
2016-09-06 12:46:28 +02:00
|
|
|
CHECK_SPLIT(DINode::FlagZero, {}, DINode::FlagZero);
|
2015-02-21 01:45:26 +01:00
|
|
|
#undef CHECK_SPLIT
|
|
|
|
}
|
|
|
|
|
2020-04-30 22:22:22 +02:00
|
|
|
TEST(StripTest, LoopMetadata) {
|
|
|
|
LLVMContext C;
|
|
|
|
std::unique_ptr<Module> M = parseIR(C, R"(
|
|
|
|
define void @f() !dbg !5 {
|
|
|
|
ret void, !dbg !10, !llvm.loop !11
|
|
|
|
}
|
|
|
|
|
|
|
|
!llvm.dbg.cu = !{!0}
|
|
|
|
!llvm.debugify = !{!3, !3}
|
|
|
|
!llvm.module.flags = !{!4}
|
|
|
|
|
|
|
|
!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
|
|
|
!1 = !DIFile(filename: "loop.ll", directory: "/")
|
|
|
|
!2 = !{}
|
|
|
|
!3 = !{i32 1}
|
|
|
|
!4 = !{i32 2, !"Debug Info Version", i32 3}
|
|
|
|
!5 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !7)
|
|
|
|
!6 = !DISubroutineType(types: !2)
|
|
|
|
!7 = !{!8}
|
|
|
|
!8 = !DILocalVariable(name: "1", scope: !5, file: !1, line: 1, type: !9)
|
|
|
|
!9 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned)
|
|
|
|
!10 = !DILocation(line: 1, column: 1, scope: !5)
|
|
|
|
!11 = distinct !{!11, !10, !10}
|
|
|
|
)");
|
|
|
|
|
|
|
|
// Look up the debug info emission kind for the CU via the loop metadata
|
|
|
|
// attached to the terminator. If, when stripping non-line table debug info,
|
|
|
|
// we update the terminator's metadata correctly, we should be able to
|
|
|
|
// observe the change in emission kind for the CU.
|
|
|
|
auto getEmissionKind = [&]() {
|
|
|
|
Instruction &I = *M->getFunction("f")->getEntryBlock().getFirstNonPHI();
|
|
|
|
MDNode *LoopMD = I.getMetadata(LLVMContext::MD_loop);
|
|
|
|
return cast<DILocation>(LoopMD->getOperand(1))
|
|
|
|
->getScope()
|
|
|
|
->getSubprogram()
|
|
|
|
->getUnit()
|
|
|
|
->getEmissionKind();
|
|
|
|
};
|
|
|
|
|
|
|
|
EXPECT_EQ(getEmissionKind(), DICompileUnit::FullDebug);
|
|
|
|
|
|
|
|
bool Changed = stripNonLineTableDebugInfo(*M);
|
|
|
|
EXPECT_TRUE(Changed);
|
|
|
|
|
|
|
|
EXPECT_EQ(getEmissionKind(), DICompileUnit::LineTablesOnly);
|
|
|
|
|
|
|
|
bool BrokenDebugInfo = false;
|
|
|
|
bool HardError = verifyModule(*M, &errs(), &BrokenDebugInfo);
|
|
|
|
EXPECT_FALSE(HardError);
|
|
|
|
EXPECT_FALSE(BrokenDebugInfo);
|
|
|
|
}
|
|
|
|
|
[Instruction] Set metadata uses to undef on deletion
Summary:
Replace any extant metadata uses of a dying instruction with undef to
preserve debug info accuracy. Some alternatives include:
- Treat Instruction like any other Value, and point its extant metadata
uses to an empty ValueAsMetadata node. This makes extant dbg.value uses
trivially dead (i.e. fair game for deletion in many passes), leading to
stale dbg.values being in effect for too long.
- Call salvageDebugInfoOrMarkUndef. Not needed to make instruction removal
correct. OTOH results in wasted work in some common cases (e.g. when all
instructions in a BasicBlock are deleted).
This came up while discussing some basic cases in
https://reviews.llvm.org/D80052.
Reviewers: jmorse, TWeaver, aprantl, dexonsmith, jdoerfert
Subscribers: jholewinski, qcolombet, hiraditya, jfb, sstefan1, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D80264
2020-05-20 03:03:22 +02:00
|
|
|
TEST(MetadataTest, DeleteInstUsedByDbgValue) {
|
|
|
|
LLVMContext C;
|
|
|
|
std::unique_ptr<Module> M = parseIR(C, R"(
|
|
|
|
define i16 @f(i16 %a) !dbg !6 {
|
|
|
|
%b = add i16 %a, 1, !dbg !11
|
|
|
|
call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
|
|
|
|
ret i16 0, !dbg !11
|
|
|
|
}
|
|
|
|
declare void @llvm.dbg.value(metadata, metadata, metadata) #0
|
|
|
|
attributes #0 = { nounwind readnone speculatable willreturn }
|
|
|
|
|
|
|
|
!llvm.dbg.cu = !{!0}
|
|
|
|
!llvm.module.flags = !{!5}
|
|
|
|
|
|
|
|
!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
|
|
|
!1 = !DIFile(filename: "t.ll", directory: "/")
|
|
|
|
!2 = !{}
|
|
|
|
!5 = !{i32 2, !"Debug Info Version", i32 3}
|
|
|
|
!6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
|
|
|
|
!7 = !DISubroutineType(types: !2)
|
|
|
|
!8 = !{!9}
|
|
|
|
!9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
|
|
|
|
!10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
|
|
|
|
!11 = !DILocation(line: 1, column: 1, scope: !6)
|
|
|
|
)");
|
|
|
|
|
|
|
|
// Find %b = add ...
|
|
|
|
Instruction &I = *M->getFunction("f")->getEntryBlock().getFirstNonPHI();
|
|
|
|
|
|
|
|
// Find the dbg.value using %b.
|
|
|
|
SmallVector<DbgValueInst *, 1> DVIs;
|
|
|
|
findDbgValues(DVIs, &I);
|
|
|
|
|
|
|
|
// Delete %b. The dbg.value should now point to undef.
|
|
|
|
I.eraseFromParent();
|
2021-03-17 16:04:27 +01:00
|
|
|
EXPECT_EQ(DVIs[0]->getNumVariableLocationOps(), 1u);
|
|
|
|
EXPECT_TRUE(isa<UndefValue>(DVIs[0]->getValue(0)));
|
[Instruction] Set metadata uses to undef on deletion
Summary:
Replace any extant metadata uses of a dying instruction with undef to
preserve debug info accuracy. Some alternatives include:
- Treat Instruction like any other Value, and point its extant metadata
uses to an empty ValueAsMetadata node. This makes extant dbg.value uses
trivially dead (i.e. fair game for deletion in many passes), leading to
stale dbg.values being in effect for too long.
- Call salvageDebugInfoOrMarkUndef. Not needed to make instruction removal
correct. OTOH results in wasted work in some common cases (e.g. when all
instructions in a BasicBlock are deleted).
This came up while discussing some basic cases in
https://reviews.llvm.org/D80052.
Reviewers: jmorse, TWeaver, aprantl, dexonsmith, jdoerfert
Subscribers: jholewinski, qcolombet, hiraditya, jfb, sstefan1, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D80264
2020-05-20 03:03:22 +02:00
|
|
|
}
|
|
|
|
|
2020-10-28 20:26:44 +01:00
|
|
|
TEST(DIBuilder, CreateFortranArrayTypeWithAttributes) {
|
|
|
|
LLVMContext Ctx;
|
|
|
|
std::unique_ptr<Module> M(new Module("MyModule", Ctx));
|
|
|
|
DIBuilder DIB(*M);
|
|
|
|
|
|
|
|
DISubrange *Subrange = DIB.getOrCreateSubrange(1,1);
|
|
|
|
SmallVector<Metadata*, 4> Subranges;
|
|
|
|
Subranges.push_back(Subrange);
|
|
|
|
DINodeArray Subscripts = DIB.getOrCreateArray(Subranges);
|
|
|
|
|
|
|
|
auto getDIExpression = [&DIB](int offset) {
|
|
|
|
SmallVector<uint64_t, 4> ops;
|
|
|
|
ops.push_back(llvm::dwarf::DW_OP_push_object_address);
|
|
|
|
DIExpression::appendOffset(ops, offset);
|
|
|
|
ops.push_back(llvm::dwarf::DW_OP_deref);
|
|
|
|
|
|
|
|
return DIB.createExpression(ops);
|
|
|
|
};
|
|
|
|
|
|
|
|
DIFile *F = DIB.createFile("main.c", "/");
|
|
|
|
DICompileUnit *CU = DIB.createCompileUnit(
|
|
|
|
dwarf::DW_LANG_C, DIB.createFile("main.c", "/"), "llvm-c", true, "", 0);
|
|
|
|
|
|
|
|
DIVariable *DataLocation =
|
|
|
|
DIB.createTempGlobalVariableFwdDecl(CU, "dl", "_dl", F, 1, nullptr, true);
|
|
|
|
DIExpression *Associated = getDIExpression(1);
|
|
|
|
DIExpression *Allocated = getDIExpression(2);
|
|
|
|
DIExpression *Rank = DIB.createConstantValueExpression(3);
|
|
|
|
|
|
|
|
DICompositeType *ArrayType = DIB.createArrayType(0, 0, nullptr, Subscripts,
|
|
|
|
DataLocation, Associated,
|
|
|
|
Allocated, Rank);
|
|
|
|
|
|
|
|
EXPECT_TRUE(isa_and_nonnull<DICompositeType>(ArrayType));
|
|
|
|
EXPECT_EQ(ArrayType->getRawDataLocation(), DataLocation);
|
|
|
|
EXPECT_EQ(ArrayType->getRawAssociated(), Associated);
|
|
|
|
EXPECT_EQ(ArrayType->getRawAllocated(), Allocated);
|
|
|
|
EXPECT_EQ(ArrayType->getRawRank(), Rank);
|
|
|
|
|
|
|
|
// Avoid memory leak.
|
|
|
|
DIVariable::deleteTemporary(DataLocation);
|
|
|
|
}
|
|
|
|
|
2021-03-30 00:02:25 +02:00
|
|
|
TEST(DIBuilder, CreateSetType) {
|
|
|
|
LLVMContext Ctx;
|
|
|
|
std::unique_ptr<Module> M(new Module("MyModule", Ctx));
|
|
|
|
DIBuilder DIB(*M);
|
2021-03-30 08:31:14 +02:00
|
|
|
DIScope *Scope = DISubprogram::getDistinct(
|
|
|
|
Ctx, nullptr, "", "", nullptr, 0, nullptr, 0, nullptr, 0, 0,
|
|
|
|
DINode::FlagZero, DISubprogram::SPFlagZero, nullptr);
|
2021-03-30 00:02:25 +02:00
|
|
|
DIType *Type = DIB.createBasicType("Int", 64, dwarf::DW_ATE_signed);
|
|
|
|
DIFile *F = DIB.createFile("main.c", "/");
|
|
|
|
|
|
|
|
DIDerivedType *SetType = DIB.createSetType(Scope, "set1", F, 1, 64, 64, Type);
|
|
|
|
EXPECT_TRUE(isa_and_nonnull<DIDerivedType>(SetType));
|
|
|
|
}
|
|
|
|
|
2014-10-03 22:01:09 +02:00
|
|
|
} // end namespace
|