mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-29 22:50:53 +03:00
1248 lines
42 KiB
C++
1248 lines
42 KiB
C++
//===-- 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();
|
||
}
|