ldc/gen/dibuilder.cpp

1248 lines
42 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//===-- gen/dibuilder.h - Debug information builder -------------*- C++ -*-===//
//
// LDC the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
#include "gen/dibuilder.h"
#include "gen/functions.h"
#include "gen/irstate.h"
#include "gen/llvmhelpers.h"
#include "gen/logger.h"
#include "gen/tollvm.h"
#include "gen/optimizer.h"
#include "ir/irfunction.h"
#include "ir/irtypeaggr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "enum.h"
#include "ldcbindings.h"
#include "module.h"
#include "mtype.h"
////////////////////////////////////////////////////////////////////////////////
#if LDC_LLVM_VER >= 306
using LLMetadata = llvm::Metadata;
#else
using LLMetadata = llvm::Value;
#endif
#if LDC_LLVM_VER >= 307
using DIFlags = llvm::DINode;
#else
using DIFlags = llvm::DIDescriptor;
#endif
namespace {
#if LDC_LLVM_VER >= 400
const auto DIFlagZero = DIFlags::FlagZero;
#else
const unsigned DIFlagZero = 0;
#endif
ldc::DIType getNullDIType() {
#if LDC_LLVM_VER >= 307
return nullptr;
#else
return llvm::DIType();
#endif
}
#if LDC_LLVM_VER >= 307
llvm::DINodeArray getEmptyDINodeArray() {
return nullptr;
}
#else
llvm::DIArray getEmptyDINodeArray() {
return llvm::DIArray();
}
#endif
llvm::StringRef uniqueIdent(Type* t) {
#if LDC_LLVM_VER >= 309
if (t->deco)
return t->deco;
#endif
return llvm::StringRef();
}
} // namespace
bool ldc::DIBuilder::mustEmitFullDebugInfo() {
// only for -g and -gc
return global.params.symdebug == 1 || global.params.symdebug == 2;
}
bool ldc::DIBuilder::mustEmitLocationsDebugInfo() {
// for -g -gc and -gline-tables-only
return global.params.symdebug > 0;
}
////////////////////////////////////////////////////////////////////////////////
// get the module the symbol is in, or - for template instances - the current
// module
Module *ldc::DIBuilder::getDefinedModule(Dsymbol *s) {
// templates are defined in current module
if (DtoIsTemplateInstance(s)) {
return IR->dmodule;
}
// array operations as well
if (FuncDeclaration *fd = s->isFuncDeclaration()) {
if (fd->isArrayOp && (willInline() || !isDruntimeArrayOp(fd))) {
return IR->dmodule;
}
}
// otherwise use the symbol's module
return s->getModule();
}
////////////////////////////////////////////////////////////////////////////////
ldc::DIBuilder::DIBuilder(IRState *const IR)
: IR(IR), DBuilder(IR->module), CUNode(nullptr),
isTargetMSVCx64(global.params.targetTriple->isWindowsMSVCEnvironment() &&
global.params.targetTriple->isArch64Bit()) {}
llvm::LLVMContext &ldc::DIBuilder::getContext() { return IR->context(); }
ldc::DIScope ldc::DIBuilder::GetCurrentScope() {
IrFunction *fn = IR->func();
if (fn->diLexicalBlocks.empty()) {
assert(static_cast<llvm::MDNode *>(fn->diSubprogram) != 0);
return fn->diSubprogram;
}
return fn->diLexicalBlocks.top();
}
void ldc::DIBuilder::Declare(const Loc &loc, llvm::Value *var,
ldc::DILocalVariable divar
#if LDC_LLVM_VER >= 306
,
ldc::DIExpression diexpr
#endif
) {
unsigned charnum = (loc.linnum ? loc.charnum : 0);
auto debugLoc = llvm::DebugLoc::get(loc.linnum, charnum, GetCurrentScope());
#if LDC_LLVM_VER < 307
llvm::Instruction *instr = DBuilder.insertDeclare(var, divar,
#if LDC_LLVM_VER >= 306
diexpr,
#endif
IR->scopebb());
instr->setDebugLoc(debugLoc);
#else // if LLVM >= 3.7
DBuilder.insertDeclare(var, divar, diexpr, debugLoc, IR->scopebb());
#endif
}
ldc::DIFile ldc::DIBuilder::CreateFile(Loc &loc) {
const char* filename = loc.filename;
if (!filename)
filename = IR->dmodule->srcfile->toChars();
llvm::SmallString<128> path(filename);
llvm::sys::fs::make_absolute(path);
return DBuilder.createFile(llvm::sys::path::filename(path),
llvm::sys::path::parent_path(path));
}
ldc::DIFile ldc::DIBuilder::CreateFile() {
Loc loc(IR->dmodule->srcfile->toChars(), 0, 0);
return CreateFile(loc);
}
ldc::DIFile ldc::DIBuilder::CreateFile(Dsymbol* decl) {
Loc loc;
for (Dsymbol* sym = decl; sym && !loc.filename; sym = sym->parent)
loc = sym->loc;
return loc.filename ? CreateFile(loc) : CreateFile();
}
ldc::DIType ldc::DIBuilder::CreateBasicType(Type *type) {
using namespace llvm::dwarf;
Type *t = type->toBasetype();
llvm::Type *T = DtoType(type);
// find encoding
unsigned Encoding;
switch (t->ty) {
case Tbool:
Encoding = DW_ATE_boolean;
break;
case Tchar:
if (global.params.targetTriple->isWindowsMSVCEnvironment()) {
// VS debugger does not support DW_ATE_UTF for char
Encoding = DW_ATE_unsigned_char;
break;
}
case Twchar:
case Tdchar:
Encoding = DW_ATE_UTF;
break;
case Tint8:
if (global.params.targetTriple->isWindowsMSVCEnvironment()) {
// VS debugger does not support DW_ATE_signed for 8-bit
Encoding = DW_ATE_signed_char;
break;
}
case Tint16:
case Tint32:
case Tint64:
case Tint128:
Encoding = DW_ATE_signed;
break;
case Tuns8:
if (global.params.targetTriple->isWindowsMSVCEnvironment()) {
// VS debugger does not support DW_ATE_unsigned for 8-bit
Encoding = DW_ATE_unsigned_char;
break;
}
case Tuns16:
case Tuns32:
case Tuns64:
case Tuns128:
Encoding = DW_ATE_unsigned;
break;
case Tfloat32:
case Tfloat64:
case Tfloat80:
Encoding = DW_ATE_float;
break;
case Timaginary32:
case Timaginary64:
case Timaginary80:
if (global.params.targetTriple->isWindowsMSVCEnvironment()) {
// DW_ATE_imaginary_float not supported by the LLVM DWARF->CodeView
// conversion
Encoding = DW_ATE_float;
break;
}
Encoding = DW_ATE_imaginary_float;
break;
case Tcomplex32:
case Tcomplex64:
case Tcomplex80:
if (global.params.targetTriple->isWindowsMSVCEnvironment()) {
// DW_ATE_complex_float not supported by the LLVM DWARF->CodeView
// conversion
return CreateComplexType(t);
}
Encoding = DW_ATE_complex_float;
break;
default:
llvm_unreachable(
"Unsupported basic type for debug info in DIBuilder::CreateBasicType");
}
return DBuilder.createBasicType(type->toChars(), // name
getTypeAllocSize(T) * 8, // size (bits)
#if LDC_LLVM_VER < 400
getABITypeAlign(T) * 8, // align (bits)
#endif
Encoding);
}
ldc::DIType ldc::DIBuilder::CreateEnumType(Type *type) {
assert(type->ty == Tenum);
llvm::Type *T = DtoType(type);
TypeEnum *te = static_cast<TypeEnum *>(type);
llvm::SmallVector<LLMetadata *, 8> subscripts;
for (auto m : *te->sym->members) {
EnumMember *em = m->isEnumMember();
llvm::StringRef Name(em->toChars());
uint64_t Val = em->value()->toInteger();
auto Subscript = DBuilder.createEnumerator(Name, Val);
subscripts.push_back(Subscript);
}
llvm::StringRef Name = te->toChars();
unsigned LineNumber = te->sym->loc.linnum;
ldc::DIFile File(CreateFile(te->sym));
return DBuilder.createEnumerationType(
GetCU(), Name, File, LineNumber,
getTypeAllocSize(T) * 8, // size (bits)
getABITypeAlign(T) * 8, // align (bits)
DBuilder.getOrCreateArray(subscripts), // subscripts
CreateTypeDescription(te->sym->memtype, false));
}
ldc::DIType ldc::DIBuilder::CreatePointerType(Type *type) {
llvm::Type *T = DtoType(type);
Type *t = type->toBasetype();
assert(t->ty == Tpointer);
// find base type
Type *nt = t->nextOf();
// translate void pointers to byte pointers
if (nt->toBasetype()->ty == Tvoid)
nt = Type::tuns8;
return DBuilder.createPointerType(CreateTypeDescription(nt, false),
getTypeAllocSize(T) * 8, // size (bits)
getABITypeAlign(T) * 8, // align (bits)
type->toChars() // name
);
}
ldc::DIType ldc::DIBuilder::CreateVectorType(Type *type) {
LLType *T = DtoType(type);
Type *t = type->toBasetype();
assert(t->ty == Tvector &&
"Only vectors allowed for debug info in DIBuilder::CreateVectorType");
TypeVector *tv = static_cast<TypeVector *>(t);
Type *te = tv->elementType();
// translate void vectors to byte vectors
if (te->toBasetype()->ty == Tvoid)
te = Type::tuns8;
int64_t Dim = tv->size(Loc()) / te->size(Loc());
LLMetadata *subscripts[] = {DBuilder.getOrCreateSubrange(0, Dim)};
return DBuilder.createVectorType(
getTypeAllocSize(T) * 8, // size (bits)
getABITypeAlign(T) * 8, // align (bits)
CreateTypeDescription(te, false), // element type
DBuilder.getOrCreateArray(subscripts) // subscripts
);
}
ldc::DIType ldc::DIBuilder::CreateComplexType(Type *type) {
llvm::Type *T = DtoType(type);
Type *t = type->toBasetype();
Type* elemtype = nullptr;
switch (t->ty) {
case Tcomplex32:
elemtype = Type::tfloat32;
break;
case Tcomplex64:
elemtype = Type::tfloat64;
break;
case Tcomplex80:
elemtype = Type::tfloat80;
break;
default:
llvm_unreachable(
"Unexpected type for debug info in DIBuilder::CreateComplexType");
}
ldc::DIFile file = CreateFile();
auto imoffset = getTypeAllocSize(DtoType(elemtype));
LLMetadata *elems[] = {
CreateMemberType(0, elemtype, file, "re", 0, PROTpublic),
CreateMemberType(0, elemtype, file, "im", imoffset, PROTpublic)};
return DBuilder.createStructType(GetCU(),
t->toChars(), // Name
file, // File
0, // LineNo
getTypeAllocSize(T) * 8, // size in bits
getABITypeAlign(T) * 8, // alignment
DIFlagZero, // What here?
getNullDIType(), // derived from
DBuilder.getOrCreateArray(elems),
0, // RunTimeLang
getNullDIType(), // VTableHolder
uniqueIdent(t)); // UniqueIdentifier
}
ldc::DIType ldc::DIBuilder::CreateMemberType(unsigned linnum, Type *type,
ldc::DIFile file,
const char *c_name,
unsigned offset, PROTKIND prot) {
Type *t = type->toBasetype();
// translate functions to function pointers
if (t->ty == Tfunction)
t = t->pointerTo();
llvm::Type *T = DtoType(t);
// find base type
ldc::DIType basetype = CreateTypeDescription(t, true);
auto Flags = DIFlagZero;
switch (prot) {
case PROTprivate:
Flags = DIFlags::FlagPrivate;
break;
case PROTprotected:
Flags = DIFlags::FlagProtected;
break;
#if LDC_LLVM_VER >= 306
case PROTpublic:
Flags = DIFlags::FlagPublic;
break;
#endif
default:
break;
}
return DBuilder.createMemberType(GetCU(),
c_name, // name
file, // file
linnum, // line number
getTypeAllocSize(T) * 8, // size (bits)
getABITypeAlign(T) * 8, // align (bits)
offset * 8, // offset (bits)
Flags, // flags
basetype // derived from
);
}
void ldc::DIBuilder::AddFields(AggregateDeclaration *sd, ldc::DIFile file,
llvm::SmallVector<LLMetadata *, 16> &elems) {
size_t narr = sd->fields.dim;
elems.reserve(narr);
for (auto vd : sd->fields) {
elems.push_back(CreateMemberType(vd->loc.linnum, vd->type, file,
vd->toChars(), vd->offset,
vd->prot().kind));
}
}
ldc::DIType ldc::DIBuilder::CreateCompositeType(Type *type) {
Type *t = type->toBasetype();
assert((t->ty == Tstruct || t->ty == Tclass) &&
"Unsupported type for debug info in DIBuilder::CreateCompositeType");
AggregateDeclaration *sd;
if (t->ty == Tstruct) {
TypeStruct *ts = static_cast<TypeStruct *>(t);
sd = ts->sym;
} else {
TypeClass *tc = static_cast<TypeClass *>(t);
sd = tc->sym;
}
assert(sd);
// Use the actual type associated with the declaration, ignoring any
// const/wrappers.
LLType *T = DtoType(sd->type);
IrTypeAggr *ir = sd->type->ctype->isAggr();
assert(ir);
if (static_cast<llvm::MDNode *>(ir->diCompositeType) != nullptr) {
return ir->diCompositeType;
}
// if we don't know the aggregate's size, we don't know enough about it
// to provide debug info. probably a forward-declared struct?
if (sd->sizeok == SIZEOKnone) {
return DBuilder.createUnspecifiedType(sd->toChars());
}
// elements
llvm::SmallVector<LLMetadata *, 16> elems;
// defaults
llvm::StringRef name = sd->toChars();
unsigned linnum = sd->loc.linnum;
ldc::DICompileUnit CU(GetCU());
assert(CU && "Compilation unit missing or corrupted");
ldc::DIFile file = CreateFile(sd);
ldc::DIType derivedFrom = getNullDIType();
// set diCompositeType to handle recursive types properly
unsigned tag = (t->ty == Tstruct) ? llvm::dwarf::DW_TAG_structure_type
: llvm::dwarf::DW_TAG_class_type;
#if LDC_LLVM_VER >= 307
ir->diCompositeType = DBuilder.createReplaceableCompositeType(
#else
ir->diCompositeType = DBuilder.createReplaceableForwardDecl(
#endif
tag, name, CU, file, linnum);
if (!sd->isInterfaceDeclaration()) // plain interfaces don't have one
{
ClassDeclaration *classDecl = sd->isClassDeclaration();
if (classDecl && classDecl->baseClass) {
derivedFrom = CreateCompositeType(classDecl->baseClass->getType());
// needs a forward declaration to add inheritence information to elems
ldc::DIType fwd =
DBuilder.createClassType(CU, // compile unit where defined
name, // name
file, // file where defined
linnum, // line number where defined
getTypeAllocSize(T) * 8, // size in bits
getABITypeAlign(T) * 8, // alignment in bits
0, // offset in bits,
DIFlags::FlagFwdDecl, // flags
derivedFrom, // DerivedFrom
getEmptyDINodeArray(),
getNullDIType(), // VTableHolder
nullptr, // TemplateParms
uniqueIdent(t)); // UniqueIdentifier
auto dt = DBuilder.createInheritance(fwd, derivedFrom, 0,
#if LDC_LLVM_VER >= 306
DIFlags::FlagPublic
#else
0
#endif
);
elems.push_back(dt);
}
AddFields(sd, file, elems);
}
auto elemsArray = DBuilder.getOrCreateArray(elems);
ldc::DIType ret;
if (t->ty == Tclass) {
ret = DBuilder.createClassType(CU, // compile unit where defined
name, // name
file, // file where defined
linnum, // line number where defined
getTypeAllocSize(T) * 8, // size in bits
getABITypeAlign(T) * 8, // alignment in bits
0, // offset in bits,
DIFlagZero, // flags
derivedFrom, // DerivedFrom
elemsArray,
getNullDIType(), // VTableHolder
nullptr, // TemplateParms
uniqueIdent(t)); // UniqueIdentifier
} else {
ret = DBuilder.createStructType(CU, // compile unit where defined
name, // name
file, // file where defined
linnum, // line number where defined
getTypeAllocSize(T) * 8, // size in bits
getABITypeAlign(T) * 8, // alignment in bits
DIFlagZero, // flags
derivedFrom, // DerivedFrom
elemsArray,
0, // RunTimeLang
getNullDIType(), // VTableHolder
uniqueIdent(t)); // UniqueIdentifier
}
#if LDC_LLVM_VER >= 307
ir->diCompositeType = DBuilder.replaceTemporary(
llvm::TempDINode(ir->diCompositeType), static_cast<llvm::DIType *>(ret));
#else
ir->diCompositeType.replaceAllUsesWith(ret);
#endif
ir->diCompositeType = ret;
return ret;
}
ldc::DIType ldc::DIBuilder::CreateArrayType(Type *type) {
llvm::Type *T = DtoType(type);
Type *t = type->toBasetype();
assert(t->ty == Tarray);
ldc::DIFile file = CreateFile();
LLMetadata *elems[] = {
CreateMemberType(0, Type::tsize_t, file, "length", 0, PROTpublic),
CreateMemberType(0, t->nextOf()->pointerTo(), file, "ptr",
global.params.is64bit ? 8 : 4, PROTpublic)};
return DBuilder.createStructType(GetCU(),
t->toChars(), // Name
file, // File
0, // LineNo
getTypeAllocSize(T) * 8, // size in bits
getABITypeAlign(T) * 8, // alignment in bits
DIFlagZero, // What here?
getNullDIType(), // derived from
DBuilder.getOrCreateArray(elems),
0, // RunTimeLang
getNullDIType(), // VTableHolder
uniqueIdent(t)); // UniqueIdentifier
}
ldc::DIType ldc::DIBuilder::CreateSArrayType(Type *type) {
llvm::Type *T = DtoType(type);
Type *t = type->toBasetype();
assert(t->ty == Tsarray);
// find base type
llvm::SmallVector<LLMetadata *, 8> subscripts;
while (t->ty == Tsarray) {
TypeSArray *tsa = static_cast<TypeSArray *>(t);
int64_t Count = tsa->dim->toInteger();
auto subscript = DBuilder.getOrCreateSubrange(0, Count);
subscripts.push_back(subscript);
t = t->nextOf();
}
// element type: void => byte, function => function pointer
t = t->toBasetype();
if (t->ty == Tvoid)
t = Type::tuns8;
else if (t->ty == Tfunction)
t = t->pointerTo();
return DBuilder.createArrayType(
getTypeAllocSize(T) * 8, // size (bits)
getABITypeAlign(T) * 8, // align (bits)
CreateTypeDescription(t, false), // element type
DBuilder.getOrCreateArray(subscripts) // subscripts
);
}
ldc::DIType ldc::DIBuilder::CreateAArrayType(Type *type) {
return CreatePointerType(Type::tvoidptr);
}
////////////////////////////////////////////////////////////////////////////////
ldc::DISubroutineType ldc::DIBuilder::CreateFunctionType(Type *type) {
assert(type->toBasetype()->ty == Tfunction);
TypeFunction *t = static_cast<TypeFunction *>(type);
Type *retType = t->next;
// Create "dummy" subroutine type for the return type
LLMetadata *params = {CreateTypeDescription(retType, true)};
#if LDC_LLVM_VER == 305
auto paramsArray = DBuilder.getOrCreateArray(params);
#else
auto paramsArray = DBuilder.getOrCreateTypeArray(params);
#endif
#if LDC_LLVM_VER >= 308
return DBuilder.createSubroutineType(paramsArray);
#else
return DBuilder.createSubroutineType(CreateFile(), paramsArray);
#endif
}
ldc::DISubroutineType ldc::DIBuilder::CreateEmptyFunctionType() {
#if LDC_LLVM_VER == 305
auto paramsArray = DBuilder.getOrCreateArray(llvm::None);
#else
auto paramsArray = DBuilder.getOrCreateTypeArray(llvm::None);
#endif
#if LDC_LLVM_VER >= 308
return DBuilder.createSubroutineType(paramsArray);
#else
return DBuilder.createSubroutineType(CreateFile(), paramsArray);
#endif
}
ldc::DIType ldc::DIBuilder::CreateDelegateType(Type *type) {
assert(type->toBasetype()->ty == Tdelegate);
llvm::Type *T = DtoType(type);
auto t = static_cast<TypeDelegate *>(type);
ldc::DICompileUnit CU(GetCU());
assert(CU && "Compilation unit missing or corrupted");
auto file = CreateFile();
LLMetadata *elems[] = {
CreateMemberType(0, Type::tvoidptr, file, "context", 0, PROTpublic),
CreateMemberType(0, t->next, file, "funcptr",
global.params.is64bit ? 8 : 4, PROTpublic)};
return DBuilder.createStructType(CU, // compile unit where defined
t->toChars(), // name
file, // file where defined
0, // line number where defined
getTypeAllocSize(T) * 8, // size in bits
getABITypeAlign(T) * 8, // alignment in bits
DIFlagZero, // flags
getNullDIType(), // derived from
DBuilder.getOrCreateArray(elems),
0, // RunTimeLang
getNullDIType(), // VTableHolder
uniqueIdent(t)); // UniqueIdentifier
}
////////////////////////////////////////////////////////////////////////////////
bool isOpaqueEnumType(Type *type) {
if (type->ty != Tenum)
return false;
TypeEnum *te = static_cast<TypeEnum *>(type);
return !te->sym->memtype;
}
ldc::DIType ldc::DIBuilder::CreateTypeDescription(Type *type, bool derefclass) {
// Check for opaque enum first, Bugzilla 13792
if (isOpaqueEnumType(type))
return DBuilder.createUnspecifiedType(type->toChars());
Type *t = type->toBasetype();
if (derefclass && t->ty == Tclass) {
type = type->pointerTo();
t = type->toBasetype();
}
if (t->ty == Tvoid)
#if LDC_LLVM_VER >= 309
return nullptr;
#else
return DBuilder.createUnspecifiedType(t->toChars());
#endif
if (t->ty == Tnull) // display null as void*
return DBuilder.createPointerType(CreateTypeDescription(Type::tvoid, false),
8, 8, "typeof(null)");
if (t->ty == Tvector)
return CreateVectorType(type);
if (t->isintegral() || t->isfloating()) {
if (type->ty == Tenum)
return CreateEnumType(type);
return CreateBasicType(type);
}
if (t->ty == Tpointer)
return CreatePointerType(type);
if (t->ty == Tarray)
return CreateArrayType(type);
if (t->ty == Tsarray)
return CreateSArrayType(type);
if (t->ty == Taarray)
return CreateAArrayType(type);
if (t->ty == Tstruct || t->ty == Tclass)
return CreateCompositeType(type);
if (t->ty == Tfunction)
return CreateFunctionType(type);
if (t->ty == Tdelegate)
return CreateDelegateType(type);
// Crash if the type is not supported.
llvm_unreachable("Unsupported type in debug info");
}
////////////////////////////////////////////////////////////////////////////////
#if LDC_LLVM_VER >= 309
using DebugEmissionKind = llvm::DICompileUnit::DebugEmissionKind;
#else
using DebugEmissionKind = llvm::DIBuilder::DebugEmissionKind;
#endif
DebugEmissionKind getDebugEmissionKind()
{
#if LDC_LLVM_VER >= 309
switch (global.params.symdebug)
{
case 0:
return llvm::DICompileUnit::NoDebug;
case 1:
case 2:
return llvm::DICompileUnit::FullDebug;
case 3:
return llvm::DICompileUnit::LineTablesOnly;
default:
llvm_unreachable("unknown DebugEmissionKind");
}
#else
assert(global.params.symdebug != 0);
return global.params.symdebug == 3 ?
llvm::DIBuilder::LineTablesOnly :
llvm::DIBuilder::FullDebug;
#endif
}
void ldc::DIBuilder::EmitCompileUnit(Module *m) {
if (!mustEmitLocationsDebugInfo()) {
return;
}
Logger::println("D to dwarf compile_unit");
LOG_SCOPE;
assert(!CUNode && "Already created compile unit for this DIBuilder instance");
// prepare srcpath
llvm::SmallString<128> srcpath(m->srcfile->name->toChars());
llvm::sys::fs::make_absolute(srcpath);
#if LDC_LLVM_VER >= 308
if (global.params.targetTriple->isWindowsMSVCEnvironment())
IR->module.addModuleFlag(llvm::Module::Warning, "CodeView", 1);
else if (global.params.dwarfVersion > 0)
IR->module.addModuleFlag(llvm::Module::Warning, "Dwarf Version",
global.params.dwarfVersion);
#endif
// Metadata without a correct version will be stripped by UpgradeDebugInfo.
IR->module.addModuleFlag(llvm::Module::Warning, "Debug Info Version",
llvm::DEBUG_METADATA_VERSION);
CUNode = DBuilder.createCompileUnit(
global.params.symdebug == 2 ? llvm::dwarf::DW_LANG_C
: llvm::dwarf::DW_LANG_D,
#if LDC_LLVM_VER >= 400
DBuilder.createFile(llvm::sys::path::filename(srcpath),
llvm::sys::path::parent_path(srcpath)),
#else
llvm::sys::path::filename(srcpath), llvm::sys::path::parent_path(srcpath),
#endif
"LDC (http://wiki.dlang.org/LDC)",
isOptimizationEnabled(), // isOptimized
llvm::StringRef(), // Flags TODO
1, // Runtime Version TODO
llvm::StringRef(), // SplitName
getDebugEmissionKind() // DebugEmissionKind
#if LDC_LLVM_VER > 306
, 0 // DWOId
#endif
#if LDC_LLVM_VER < 309
, mustEmitFullDebugInfo() // EmitDebugInfo
#endif
);
}
ldc::DISubprogram ldc::DIBuilder::EmitSubProgram(FuncDeclaration *fd) {
if (!mustEmitLocationsDebugInfo()) {
#if LDC_LLVM_VER >= 307
return nullptr;
#else
return llvm::DISubprogram();
#endif
}
Logger::println("D to dwarf subprogram");
LOG_SCOPE;
ldc::DICompileUnit CU(GetCU());
assert(CU &&
"Compilation unit missing or corrupted in DIBuilder::EmitSubProgram");
ldc::DIFile file = CreateFile(fd);
// Create subroutine type
ldc::DISubroutineType DIFnType = mustEmitFullDebugInfo() ?
CreateFunctionType(static_cast<TypeFunction *>(fd->type)) :
CreateEmptyFunctionType();
// FIXME: duplicates?
auto SP = DBuilder.createFunction(
CU, // context
fd->toPrettyChars(), // name
getIrFunc(fd)->getLLVMFuncName(), // linkage name
file, // file
fd->loc.linnum, // line no
DIFnType, // type
fd->protection.kind == PROTprivate, // is local to unit
true, // isdefinition
fd->loc.linnum, // FIXME: scope line
DIFlags::FlagPrototyped, // Flags
isOptimizationEnabled() // isOptimized
#if LDC_LLVM_VER < 308
,
DtoFunction(fd)
#endif
);
#if LDC_LLVM_VER >= 308
if (fd->fbody)
DtoFunction(fd)->setSubprogram(SP);
#endif
return SP;
}
ldc::DISubprogram ldc::DIBuilder::EmitThunk(llvm::Function *Thunk,
FuncDeclaration *fd) {
if (!mustEmitLocationsDebugInfo()) {
#if LDC_LLVM_VER >= 307
return nullptr;
#else
return llvm::DISubprogram();
#endif
}
Logger::println("Thunk to dwarf subprogram");
LOG_SCOPE;
ldc::DICompileUnit CU(GetCU());
assert(CU && "Compilation unit missing or corrupted in DIBuilder::EmitThunk");
ldc::DIFile file = CreateFile(fd);
// Create subroutine type (thunk has same type as wrapped function)
ldc::DISubroutineType DIFnType = CreateFunctionType(fd->type);
std::string name = fd->toPrettyChars();
name.append(".__thunk");
// FIXME: duplicates?
auto SP = DBuilder.createFunction(
CU, // context
name, // name
Thunk->getName(), // linkage name
file, // file
fd->loc.linnum, // line no
DIFnType, // type
fd->protection.kind == PROTprivate, // is local to unit
true, // isdefinition
fd->loc.linnum, // FIXME: scope line
DIFlags::FlagPrototyped, // Flags
isOptimizationEnabled() // isOptimized
#if LDC_LLVM_VER < 308
,
DtoFunction(fd)
#endif
);
#if LDC_LLVM_VER >= 308
if (fd->fbody)
DtoFunction(fd)->setSubprogram(SP);
#endif
return SP;
}
ldc::DISubprogram ldc::DIBuilder::EmitModuleCTor(llvm::Function *Fn,
llvm::StringRef prettyname) {
if (!mustEmitLocationsDebugInfo()) {
#if LDC_LLVM_VER >= 307
return nullptr;
#else
return llvm::DISubprogram();
#endif
}
Logger::println("D to dwarf subprogram");
LOG_SCOPE;
ldc::DICompileUnit CU(GetCU());
assert(CU &&
"Compilation unit missing or corrupted in DIBuilder::EmitSubProgram");
ldc::DIFile file = CreateFile();
// Create "dummy" subroutine type for the return type
LLMetadata *params = {CreateTypeDescription(Type::tvoid, true)};
#if LDC_LLVM_VER >= 306
auto paramsArray = DBuilder.getOrCreateTypeArray(params);
#else
auto paramsArray = DBuilder.getOrCreateArray(params);
#endif
#if LDC_LLVM_VER >= 308
auto DIFnType = DBuilder.createSubroutineType(paramsArray);
#else
auto DIFnType = DBuilder.createSubroutineType(file, paramsArray);
#endif
// FIXME: duplicates?
auto SP =
DBuilder.createFunction(CU, // context
prettyname, // name
Fn->getName(), // linkage name
file, // file
0, // line no
DIFnType, // return type. TODO: fill it up
true, // is local to unit
true, // isdefinition
0, // FIXME: scope line
DIFlags::FlagPrototyped | DIFlags::FlagArtificial,
isOptimizationEnabled() // isOptimized
#if LDC_LLVM_VER < 308
,
Fn
#endif
);
#if LDC_LLVM_VER >= 308
Fn->setSubprogram(SP);
#endif
return SP;
}
void ldc::DIBuilder::EmitFuncStart(FuncDeclaration *fd) {
if (!mustEmitLocationsDebugInfo())
return;
Logger::println("D to dwarf funcstart");
LOG_SCOPE;
assert(static_cast<llvm::MDNode *>(getIrFunc(fd)->diSubprogram) != 0);
EmitStopPoint(fd->loc);
}
void ldc::DIBuilder::EmitFuncEnd(FuncDeclaration *fd) {
if (!mustEmitLocationsDebugInfo())
return;
Logger::println("D to dwarf funcend");
LOG_SCOPE;
assert(static_cast<llvm::MDNode *>(getIrFunc(fd)->diSubprogram) != 0);
EmitStopPoint(fd->endloc);
}
void ldc::DIBuilder::EmitBlockStart(Loc &loc) {
if (!mustEmitLocationsDebugInfo())
return;
Logger::println("D to dwarf block start");
LOG_SCOPE;
ldc::DILexicalBlock block =
DBuilder.createLexicalBlock(GetCurrentScope(), // scope
CreateFile(loc), // file
loc.linnum, // line
loc.linnum ? loc.charnum : 0 // column
#if LDC_LLVM_VER == 305
,
0 // DWARF path discriminator value
#endif
);
IR->func()->diLexicalBlocks.push(block);
EmitStopPoint(loc);
}
void ldc::DIBuilder::EmitBlockEnd() {
if (!mustEmitLocationsDebugInfo())
return;
Logger::println("D to dwarf block end");
LOG_SCOPE;
IrFunction *fn = IR->func();
assert(!fn->diLexicalBlocks.empty());
fn->diLexicalBlocks.pop();
}
void ldc::DIBuilder::EmitStopPoint(Loc &loc) {
if (!mustEmitLocationsDebugInfo())
return;
// If we already have a location set and the current loc is invalid
// (line 0), then we can just ignore it (see GitHub issue #998 for why we
// cannot do this in all cases).
#if LDC_LLVM_VER >= 307
if (!loc.linnum && IR->ir->getCurrentDebugLocation())
return;
#else
if (!loc.linnum && !IR->ir->getCurrentDebugLocation().isUnknown())
return;
#endif
unsigned linnum = loc.linnum;
// without proper loc use the line of the enclosing symbol that has line
// number debug info
for (Dsymbol *sym = IR->func()->decl; sym && !linnum; sym = sym->parent)
linnum = sym->loc.linnum;
if (!linnum)
linnum = 1;
unsigned charnum = (loc.linnum ? loc.charnum : 0);
Logger::println("D to dwarf stoppoint at line %u, column %u", linnum,
charnum);
LOG_SCOPE;
IR->ir->SetCurrentDebugLocation(
llvm::DebugLoc::get(linnum, charnum, GetCurrentScope()));
currentLoc = loc;
}
Loc ldc::DIBuilder::GetCurrentLoc() const { return currentLoc; }
void ldc::DIBuilder::EmitValue(llvm::Value *val, VarDeclaration *vd) {
auto sub = IR->func()->variableMap.find(vd);
if (sub == IR->func()->variableMap.end())
return;
ldc::DILocalVariable debugVariable = sub->second;
if (!mustEmitFullDebugInfo() || !debugVariable)
return;
llvm::Instruction *instr =
DBuilder.insertDbgValueIntrinsic(val, 0, debugVariable,
#if LDC_LLVM_VER >= 306
DBuilder.createExpression(),
#endif
#if LDC_LLVM_VER >= 307
IR->ir->getCurrentDebugLocation(),
#endif
IR->scopebb());
instr->setDebugLoc(IR->ir->getCurrentDebugLocation());
}
void ldc::DIBuilder::EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd,
Type *type, bool isThisPtr,
bool forceAsLocal,
#if LDC_LLVM_VER >= 306
llvm::ArrayRef<int64_t> addr
#else
llvm::ArrayRef<llvm::Value *> addr
#endif
) {
if (!mustEmitFullDebugInfo())
return;
Logger::println("D to dwarf local variable");
LOG_SCOPE;
auto &variableMap = IR->func()->variableMap;
auto sub = variableMap.find(vd);
if (sub != variableMap.end())
return; // ensure that the debug variable is created only once
// get type description
if (!type)
type = vd->type;
ldc::DIType TD = CreateTypeDescription(type, true);
if (static_cast<llvm::MDNode *>(TD) == nullptr)
return; // unsupported
if (vd->storage_class & (STCref | STCout)) {
#if LDC_LLVM_VER >= 308
auto T = DtoType(type);
TD = DBuilder.createReferenceType(llvm::dwarf::DW_TAG_reference_type, TD,
getTypeAllocSize(T) * 8, // size (bits)
DtoAlignment(type) * 8); // align (bits)
#else
TD = DBuilder.createReferenceType(llvm::dwarf::DW_TAG_reference_type, TD);
#endif
} else {
// FIXME: For MSVC x64 targets, declare dynamic array and vector parameters
// as DI locals to work around garbage for both cdb and VS debuggers.
if (isTargetMSVCx64) {
TY ty = type->toBasetype()->ty;
if (ty == Tarray || ty == Tvector)
forceAsLocal = true;
}
}
// get variable description
assert(!vd->isDataseg() && "static variable");
#if LDC_LLVM_VER < 308
unsigned tag;
if (!forceAsLocal && vd->isParameter()) {
tag = llvm::dwarf::DW_TAG_arg_variable;
} else {
tag = llvm::dwarf::DW_TAG_auto_variable;
}
#endif
ldc::DILocalVariable debugVariable;
auto Flags = !isThisPtr
? DIFlagZero
: DIFlags::FlagArtificial | DIFlags::FlagObjectPointer;
#if LDC_LLVM_VER < 306
if (addr.empty()) {
debugVariable = DBuilder.createLocalVariable(tag, // tag
GetCurrentScope(), // scope
vd->toChars(), // name
CreateFile(vd), // file
vd->loc.linnum, // line num
TD, // type
true, // preserve
Flags // flags
);
} else {
debugVariable = DBuilder.createComplexVariable(tag, // tag
GetCurrentScope(), // scope
vd->toChars(), // name
CreateFile(vd), // file
vd->loc.linnum, // line num
TD, // type
addr);
}
#elif LDC_LLVM_VER < 308
debugVariable = DBuilder.createLocalVariable(tag, // tag
GetCurrentScope(), // scope
vd->toChars(), // name
CreateFile(vd), // file
vd->loc.linnum, // line num
TD, // type
true, // preserve
Flags // flags
);
#else
if (!forceAsLocal && vd->isParameter()) {
FuncDeclaration *fd = vd->parent->isFuncDeclaration();
assert(fd);
size_t argNo = 0;
if (fd->vthis != vd) {
assert(fd->parameters);
for (argNo = 0; argNo < fd->parameters->dim; argNo++) {
if ((*fd->parameters)[argNo] == vd)
break;
}
assert(argNo < fd->parameters->dim);
if (fd->vthis)
argNo++;
}
debugVariable = DBuilder.createParameterVariable(GetCurrentScope(), // scope
vd->toChars(), // name
argNo + 1,
CreateFile(vd), // file
vd->loc.linnum, // line num
TD, // type
true, // preserve
Flags // flags
);
} else {
debugVariable = DBuilder.createAutoVariable(GetCurrentScope(), // scope
vd->toChars(), // name
CreateFile(vd), // file
vd->loc.linnum, // line num
TD, // type
true, // preserve
Flags // flags
);
}
#endif
variableMap[vd] = debugVariable;
// declare
#if LDC_LLVM_VER >= 306
Declare(vd->loc, ll, debugVariable, addr.empty()
? DBuilder.createExpression()
: DBuilder.createExpression(addr));
#else
Declare(vd->loc, ll, debugVariable);
#endif
}
void ldc::DIBuilder::EmitGlobalVariable(llvm::GlobalVariable *llVar,
VarDeclaration *vd) {
if (!mustEmitFullDebugInfo())
return;
Logger::println("D to dwarf global_variable");
LOG_SCOPE;
assert(vd->isDataseg() ||
(vd->storage_class & (STCconst | STCimmutable) && vd->_init));
#if LDC_LLVM_VER >= 400
auto DIVar = DBuilder.createGlobalVariableExpression(
#else
DBuilder.createGlobalVariable(
#endif
#if LDC_LLVM_VER >= 306
GetCU(), // context
#endif
vd->toChars(), // name
mangle(vd), // linkage name
CreateFile(vd), // file
vd->loc.linnum, // line num
CreateTypeDescription(vd->type, false), // type
vd->protection.kind == PROTprivate, // is local to unit
#if LDC_LLVM_VER >= 400
nullptr // relative location of field
#else
llVar // value
#endif
);
#if LDC_LLVM_VER >= 400
llVar->addDebugInfo(DIVar);
#endif
}
void ldc::DIBuilder::Finalize() {
if (!mustEmitLocationsDebugInfo())
return;
DBuilder.finalize();
}