mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-01 07:30:43 +03:00
Introduce a debug info builder.
Moves all code from todebug into a new class. Also caches the compilation unit in order to fix a LLVM 3.4 compile error.
This commit is contained in:
parent
4e8acf7eb6
commit
c28c7fb134
14 changed files with 521 additions and 493 deletions
736
gen/dibuilder.cpp
Normal file
736
gen/dibuilder.cpp
Normal file
|
@ -0,0 +1,736 @@
|
|||
//===-- 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/irstate.h"
|
||||
#include "gen/llvmhelpers.h"
|
||||
#include "gen/logger.h"
|
||||
#include "gen/tollvm.h"
|
||||
#include "gen/utils.h"
|
||||
#include "ir/irtypeaggr.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "enum.h"
|
||||
#include "module.h"
|
||||
#include "mtype.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 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, true))
|
||||
{
|
||||
return IR->dmodule;
|
||||
}
|
||||
// array operations as well
|
||||
else if (FuncDeclaration* fd = s->isFuncDeclaration())
|
||||
{
|
||||
if (fd->isArrayOp == 1)
|
||||
return IR->dmodule;
|
||||
}
|
||||
// otherwise use the symbol's module
|
||||
return s->getModule();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ldc::DIBuilder::DIBuilder(IRState *const IR, llvm::Module &M)
|
||||
: IR(IR), DBuilder(M)
|
||||
{
|
||||
}
|
||||
|
||||
llvm::LLVMContext &ldc::DIBuilder::getContext()
|
||||
{
|
||||
return IR->context();
|
||||
}
|
||||
|
||||
llvm::DIDescriptor 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(llvm::Value *var, llvm::DIVariable divar)
|
||||
{
|
||||
llvm::Instruction *instr = DBuilder.insertDeclare(var, divar, IR->scopebb());
|
||||
instr->setDebugLoc(IR->ir->getCurrentDebugLocation());
|
||||
}
|
||||
|
||||
llvm::DIFile ldc::DIBuilder::CreateFile(Loc loc)
|
||||
{
|
||||
llvm::SmallString<128> path(loc.filename ? loc.filename : "");
|
||||
llvm::sys::fs::make_absolute(path);
|
||||
|
||||
return DBuilder.createFile(
|
||||
llvm::sys::path::filename(path),
|
||||
llvm::sys::path::parent_path(path)
|
||||
);
|
||||
}
|
||||
|
||||
llvm::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:
|
||||
case Twchar:
|
||||
case Tdchar:
|
||||
Encoding = type->isunsigned() ? DW_ATE_unsigned_char
|
||||
: DW_ATE_signed_char;
|
||||
break;
|
||||
case Tint8:
|
||||
case Tint16:
|
||||
case Tint32:
|
||||
case Tint64:
|
||||
case Tint128:
|
||||
Encoding = DW_ATE_signed;
|
||||
break;
|
||||
case Tuns8:
|
||||
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:
|
||||
Encoding = DW_ATE_imaginary_float;
|
||||
break;
|
||||
case Tcomplex32:
|
||||
case Tcomplex64:
|
||||
case Tcomplex80:
|
||||
Encoding = DW_ATE_complex_float;
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Unsupported basic type for debug info in DIBuilder::CreateBasicType");
|
||||
}
|
||||
|
||||
return DBuilder.createBasicType(
|
||||
type->toChars(), // name
|
||||
getTypeBitSize(T), // size (bits)
|
||||
getABITypeAlign(T)*8, // align (bits)
|
||||
Encoding
|
||||
);
|
||||
}
|
||||
|
||||
llvm::DIType ldc::DIBuilder::CreateEnumType(Type *type)
|
||||
{
|
||||
llvm::Type *T = DtoType(type);
|
||||
|
||||
assert(type->ty == Tenum && "only enums allowed for debug info in dwarfEnumType");
|
||||
TypeEnum *te = static_cast<TypeEnum *>(type);
|
||||
llvm::SmallVector<llvm::Value *, 8> subscripts;
|
||||
for (ArrayIter<Dsymbol> it(te->sym->members); it.more(); it.next())
|
||||
{
|
||||
EnumMember *em = it->isEnumMember();
|
||||
llvm::StringRef Name(em->toChars());
|
||||
uint64_t Val = em->value->toInteger();
|
||||
llvm::Value *Subscript = DBuilder.createEnumerator(Name, Val);
|
||||
subscripts.push_back(Subscript);
|
||||
}
|
||||
|
||||
llvm::StringRef Name = te->toChars();
|
||||
unsigned LineNumber = te->sym->loc.linnum;
|
||||
llvm::DIFile File = CreateFile(te->sym->loc);
|
||||
|
||||
return DBuilder.createEnumerationType(
|
||||
llvm::DICompileUnit(GetCU()),
|
||||
Name,
|
||||
File,
|
||||
LineNumber,
|
||||
getTypeBitSize(T), // size (bits)
|
||||
getABITypeAlign(T)*8, // align (bits)
|
||||
DBuilder.getOrCreateArray(subscripts) // subscripts
|
||||
#if LDC_LLVM_VER >= 302
|
||||
, CreateTypeDescription(te->sym->memtype, NULL)
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
llvm::DIType ldc::DIBuilder::CreatePointerType(Type *type)
|
||||
{
|
||||
llvm::Type *T = DtoType(type);
|
||||
Type *t = type->toBasetype();
|
||||
|
||||
assert(t->ty == Tpointer && "Only pointers allowed for debug info in DIBuilder::CreatePointerType");
|
||||
|
||||
// find base type
|
||||
Type *nt = t->nextOf();
|
||||
llvm::DIType basetype = CreateTypeDescription(nt, NULL);
|
||||
if (nt->ty == Tvoid)
|
||||
basetype = llvm::DIType(NULL);
|
||||
|
||||
return DBuilder.createPointerType(
|
||||
basetype,
|
||||
getTypeBitSize(T), // size (bits)
|
||||
getABITypeAlign(T)*8, // align (bits)
|
||||
type->toChars() // name
|
||||
);
|
||||
}
|
||||
|
||||
llvm::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();
|
||||
int64_t Dim = tv->size(Loc()) / te->size(Loc());
|
||||
llvm::Value *subscripts[] =
|
||||
{
|
||||
DBuilder.getOrCreateSubrange(0, Dim)
|
||||
};
|
||||
llvm::DIType basetype = CreateTypeDescription(te, NULL);
|
||||
|
||||
return DBuilder.createVectorType(
|
||||
getTypeBitSize(T), // size (bits)
|
||||
getABITypeAlign(T)*8, // align (bits)
|
||||
basetype, // element type
|
||||
DBuilder.getOrCreateArray(subscripts) // subscripts
|
||||
);
|
||||
}
|
||||
|
||||
llvm::DIType ldc::DIBuilder::CreateMemberType(unsigned linnum, Type *type,
|
||||
llvm::DIFile file,
|
||||
const char* c_name,
|
||||
unsigned offset)
|
||||
{
|
||||
llvm::Type *T = DtoType(type);
|
||||
Type *t = type->toBasetype();
|
||||
|
||||
// find base type
|
||||
llvm::DIType basetype = CreateTypeDescription(t, NULL, true);
|
||||
if (t->ty == Tvoid)
|
||||
basetype = llvm::DIType(NULL);
|
||||
|
||||
return DBuilder.createMemberType(
|
||||
llvm::DICompileUnit(GetCU()),
|
||||
c_name, // name
|
||||
file, // file
|
||||
linnum, // line number
|
||||
getTypeBitSize(T), // size (bits)
|
||||
getABITypeAlign(T)*8, // align (bits)
|
||||
offset*8, // offset (bits)
|
||||
//FIXME: need flags?
|
||||
0, // flags
|
||||
basetype // derived from
|
||||
);
|
||||
}
|
||||
|
||||
void ldc::DIBuilder::AddBaseFields(ClassDeclaration *sd, llvm::DIFile file,
|
||||
std::vector<llvm::Value*> &elems)
|
||||
{
|
||||
if (sd->baseClass)
|
||||
{
|
||||
AddBaseFields(sd->baseClass, file, elems);
|
||||
}
|
||||
|
||||
ArrayIter<VarDeclaration> it(sd->fields);
|
||||
size_t narr = sd->fields.dim;
|
||||
elems.reserve(narr);
|
||||
for (; !it.done(); it.next())
|
||||
{
|
||||
VarDeclaration* vd = it.get();
|
||||
elems.push_back(CreateMemberType(vd->loc.linnum, vd->type, file, vd->toChars(), vd->offset));
|
||||
}
|
||||
}
|
||||
|
||||
llvm::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->irtype->isAggr();
|
||||
assert(ir);
|
||||
|
||||
if (static_cast<llvm::MDNode *>(ir->diCompositeType) != 0)
|
||||
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 == 0)
|
||||
return llvm::DICompositeType(NULL);
|
||||
|
||||
// elements
|
||||
std::vector<llvm::Value *> elems;
|
||||
|
||||
// defaults
|
||||
llvm::StringRef name = sd->toChars();
|
||||
unsigned linnum = sd->loc.linnum;
|
||||
llvm::DICompileUnit CU(GetCU());
|
||||
assert(CU && CU.Verify() && "Compilation unit missing or corrupted");
|
||||
llvm::DIFile file = CreateFile(sd->loc);
|
||||
llvm::DIType derivedFrom;
|
||||
|
||||
// set diCompositeType to handle recursive types properly
|
||||
unsigned tag = (t->ty == Tstruct) ? llvm::dwarf::DW_TAG_structure_type
|
||||
: llvm::dwarf::DW_TAG_class_type;
|
||||
ir->diCompositeType = DBuilder.createForwardDecl(tag, name,
|
||||
#if LDC_LLVM_VER >= 302
|
||||
CU,
|
||||
#endif
|
||||
file, linnum);
|
||||
|
||||
if (!sd->isInterfaceDeclaration()) // plain interfaces don't have one
|
||||
{
|
||||
if (t->ty == Tstruct)
|
||||
{
|
||||
ArrayIter<VarDeclaration> it(sd->fields);
|
||||
size_t narr = sd->fields.dim;
|
||||
elems.reserve(narr);
|
||||
for (; !it.done(); it.next())
|
||||
{
|
||||
VarDeclaration* vd = it.get();
|
||||
llvm::DIType dt = CreateMemberType(vd->loc.linnum, vd->type, file, vd->toChars(), vd->offset);
|
||||
elems.push_back(dt);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ClassDeclaration *classDecl = sd->isClassDeclaration();
|
||||
AddBaseFields(classDecl, file, elems);
|
||||
if (classDecl->baseClass)
|
||||
derivedFrom = CreateCompositeType(classDecl->baseClass->getType());
|
||||
}
|
||||
}
|
||||
|
||||
llvm::DIArray elemsArray = DBuilder.getOrCreateArray(elems);
|
||||
|
||||
llvm::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
|
||||
getTypeBitSize(T), // size in bits
|
||||
getABITypeAlign(T)*8, // alignment in bits
|
||||
0, // offset in bits,
|
||||
llvm::DIType::FlagFwdDecl, // flags
|
||||
derivedFrom, // DerivedFrom
|
||||
elemsArray
|
||||
);
|
||||
} else {
|
||||
ret = DBuilder.createStructType(
|
||||
CU, // compile unit where defined
|
||||
name, // name
|
||||
file, // file where defined
|
||||
linnum, // line number where defined
|
||||
getTypeBitSize(T), // size in bits
|
||||
getABITypeAlign(T)*8, // alignment in bits
|
||||
llvm::DIType::FlagFwdDecl, // flags
|
||||
#if LDC_LLVM_VER >= 303
|
||||
derivedFrom, // DerivedFrom
|
||||
#endif
|
||||
elemsArray
|
||||
);
|
||||
}
|
||||
|
||||
ir->diCompositeType.replaceAllUsesWith(ret);
|
||||
ir->diCompositeType = ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
llvm::DIType ldc::DIBuilder::CreateArrayType(Type *type)
|
||||
{
|
||||
llvm::Type *T = DtoType(type);
|
||||
Type *t = type->toBasetype();
|
||||
|
||||
assert(t->ty == Tarray && "Only arrays allowed for debug info in DIBuilder::CreateArrayType");
|
||||
|
||||
llvm::DIFile file = CreateFile(Loc(IR->dmodule, 0));
|
||||
|
||||
llvm::Value *elems[] = {
|
||||
CreateMemberType(0, Type::tsize_t, file, "length", 0),
|
||||
CreateMemberType(0, t->nextOf()->pointerTo(), file, "ptr",
|
||||
global.params.is64bit ? 8 : 4)
|
||||
};
|
||||
|
||||
return DBuilder.createStructType
|
||||
(
|
||||
llvm::DICompileUnit(GetCU()),
|
||||
llvm::StringRef(), // Name TODO: Really no name for arrays? t->toChars()?
|
||||
file, // File
|
||||
0, // LineNo
|
||||
getTypeBitSize(T), // size in bits
|
||||
getABITypeAlign(T)*8, // alignment in bits
|
||||
0, // What here?
|
||||
#if LDC_LLVM_VER >= 303
|
||||
llvm::DIType(), // DerivedFrom
|
||||
#endif
|
||||
DBuilder.getOrCreateArray(elems)
|
||||
);
|
||||
}
|
||||
|
||||
llvm::DIType ldc::DIBuilder::CreateSArrayType(Type *type)
|
||||
{
|
||||
llvm::Type *T = DtoType(type);
|
||||
Type *t = type->toBasetype();
|
||||
|
||||
// find base type
|
||||
llvm::SmallVector<llvm::Value *, 8> subscripts;
|
||||
while (t->ty == Tsarray)
|
||||
{
|
||||
TypeSArray *tsa = static_cast<TypeSArray *>(t);
|
||||
int64_t Count = tsa->dim->toInteger();
|
||||
llvm::Value *subscript = DBuilder.getOrCreateSubrange(0, Count-1);
|
||||
subscripts.push_back(subscript);
|
||||
t = t->nextOf();
|
||||
}
|
||||
llvm::DIType basetype = CreateTypeDescription(t, NULL);
|
||||
|
||||
return DBuilder.createArrayType(
|
||||
getTypeBitSize(T), // size (bits)
|
||||
getABITypeAlign(T)*8, // align (bits)
|
||||
basetype, // element type
|
||||
DBuilder.getOrCreateArray(subscripts) // subscripts
|
||||
);
|
||||
}
|
||||
|
||||
llvm::DIType ldc::DIBuilder::CreateTypeDescription(Type* type,
|
||||
const char* c_name,
|
||||
bool derefclass)
|
||||
{
|
||||
Type *t = type->toBasetype();
|
||||
if (derefclass && t->ty == Tclass)
|
||||
{
|
||||
type = type->pointerTo();
|
||||
t = type->toBasetype();
|
||||
}
|
||||
|
||||
if (t->ty == Tvoid)
|
||||
return llvm::DIType(NULL);
|
||||
else if (t->isintegral() || t->isfloating())
|
||||
{
|
||||
if (t->ty == Tvector)
|
||||
return CreateVectorType(type);
|
||||
if (type->ty == Tenum)
|
||||
return CreateEnumType(type);
|
||||
return CreateBasicType(type);
|
||||
}
|
||||
else if (t->ty == Tpointer)
|
||||
return CreatePointerType(type);
|
||||
else if (t->ty == Tarray)
|
||||
return CreateArrayType(type);
|
||||
else if (t->ty == Tsarray)
|
||||
return CreateSArrayType(type);
|
||||
else if (t->ty == Tstruct || t->ty == Tclass)
|
||||
return CreateCompositeType(type);
|
||||
|
||||
return llvm::DIType(NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ldc::DIBuilder::EmitCompileUnit(Module *m)
|
||||
{
|
||||
if (!global.params.symdebug)
|
||||
return;
|
||||
|
||||
Logger::println("D to dwarf compile_unit");
|
||||
LOG_SCOPE;
|
||||
|
||||
// prepare srcpath
|
||||
llvm::SmallString<128> srcpath(m->srcfile->name->toChars());
|
||||
llvm::sys::fs::make_absolute(srcpath);
|
||||
|
||||
#if LDC_LLVM_VER >= 304
|
||||
CUNode =
|
||||
#endif
|
||||
DBuilder.createCompileUnit(
|
||||
global.params.symdebug == 2 ? llvm::dwarf::DW_LANG_C
|
||||
: llvm::dwarf::DW_LANG_D,
|
||||
llvm::sys::path::filename(srcpath),
|
||||
llvm::sys::path::parent_path(srcpath),
|
||||
"LDC (http://wiki.dlang.org/LDC)",
|
||||
false, // isOptimized TODO
|
||||
llvm::StringRef(), // Flags TODO
|
||||
1 // Runtime Version TODO
|
||||
);
|
||||
#if LDC_LLVM_VER < 304
|
||||
CUNode = DBuilder.getCU();
|
||||
#endif
|
||||
}
|
||||
|
||||
llvm::DISubprogram ldc::DIBuilder::EmitSubProgram(FuncDeclaration *fd)
|
||||
{
|
||||
if (!global.params.symdebug)
|
||||
return llvm::DISubprogram();
|
||||
|
||||
Logger::println("D to dwarf subprogram");
|
||||
LOG_SCOPE;
|
||||
|
||||
llvm::DICompileUnit CU(GetCU());
|
||||
assert(CU && CU.Verify() && "Compilation unit missing or corrupted in DIBuilder::EmitSubProgram");
|
||||
|
||||
llvm::DIFile file = CreateFile(fd->loc);
|
||||
Type *retType = static_cast<TypeFunction*>(fd->type)->next;
|
||||
|
||||
// Create "dummy" subroutine type for the return type
|
||||
llvm::SmallVector<llvm::Value*, 16> Elts;
|
||||
Elts.push_back(CreateTypeDescription(retType, NULL, true));
|
||||
llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
|
||||
#if LDC_LLVM_VER >= 304
|
||||
llvm::DICompositeType
|
||||
#else
|
||||
llvm::DIType
|
||||
#endif
|
||||
DIFnType = DBuilder.createSubroutineType(file, EltTypeArray);
|
||||
|
||||
// FIXME: duplicates ?
|
||||
return DBuilder.createFunction(
|
||||
CU, // context
|
||||
fd->toPrettyChars(), // name
|
||||
fd->mangle(), // linkage name
|
||||
file, // file
|
||||
fd->loc.linnum, // line no
|
||||
DIFnType, // type
|
||||
fd->protection == PROTprivate, // is local to unit
|
||||
IR->dmodule == getDefinedModule(fd), // isdefinition
|
||||
fd->loc.linnum, // FIXME: scope line
|
||||
0, // Flags
|
||||
false, // isOptimized
|
||||
fd->ir.irFunc->func
|
||||
);
|
||||
}
|
||||
|
||||
llvm::DISubprogram ldc::DIBuilder::EmitSubProgramInternal(llvm::StringRef prettyname,
|
||||
llvm::StringRef mangledname)
|
||||
{
|
||||
if (!global.params.symdebug)
|
||||
return llvm::DISubprogram();
|
||||
|
||||
Logger::println("D to dwarf subprogram");
|
||||
LOG_SCOPE;
|
||||
|
||||
llvm::DIFile file(CreateFile(Loc(IR->dmodule, 0)));
|
||||
|
||||
// Create "dummy" subroutine type for the return type
|
||||
llvm::SmallVector<llvm::Value *, 1> Elts;
|
||||
Elts.push_back(llvm::DIType(NULL));
|
||||
llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
|
||||
#if LDC_LLVM_VER >= 304
|
||||
llvm::DICompositeType
|
||||
#else
|
||||
llvm::DIType
|
||||
#endif
|
||||
DIFnType = DBuilder.createSubroutineType(file, EltTypeArray);
|
||||
|
||||
// FIXME: duplicates ?
|
||||
return DBuilder.createFunction(
|
||||
llvm::DIDescriptor(file), // context
|
||||
prettyname, // name
|
||||
mangledname, // 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
|
||||
);
|
||||
}
|
||||
|
||||
void ldc::DIBuilder::EmitFuncStart(FuncDeclaration *fd)
|
||||
{
|
||||
if (!global.params.symdebug)
|
||||
return;
|
||||
|
||||
Logger::println("D to dwarf funcstart");
|
||||
LOG_SCOPE;
|
||||
|
||||
assert(static_cast<llvm::MDNode *>(fd->ir.irFunc->diSubprogram) != 0);
|
||||
EmitStopPoint(fd->loc.linnum);
|
||||
}
|
||||
|
||||
void ldc::DIBuilder::EmitFuncEnd(FuncDeclaration *fd)
|
||||
{
|
||||
if (!global.params.symdebug)
|
||||
return;
|
||||
|
||||
Logger::println("D to dwarf funcend");
|
||||
LOG_SCOPE;
|
||||
|
||||
assert(static_cast<llvm::MDNode *>(fd->ir.irFunc->diSubprogram) != 0);
|
||||
}
|
||||
|
||||
void ldc::DIBuilder::EmitBlockStart(Loc loc)
|
||||
{
|
||||
if (!global.params.symdebug)
|
||||
return;
|
||||
|
||||
Logger::println("D to dwarf block start");
|
||||
LOG_SCOPE;
|
||||
|
||||
llvm::DILexicalBlock block = DBuilder.createLexicalBlock(
|
||||
GetCurrentScope(), // scope
|
||||
CreateFile(loc), // file
|
||||
loc.linnum, // line
|
||||
0 // column
|
||||
);
|
||||
IR->func()->diLexicalBlocks.push(block);
|
||||
EmitStopPoint(loc.linnum);
|
||||
}
|
||||
|
||||
void ldc::DIBuilder::EmitBlockEnd()
|
||||
{
|
||||
if (!global.params.symdebug)
|
||||
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(unsigned ln)
|
||||
{
|
||||
if (!global.params.symdebug)
|
||||
return;
|
||||
|
||||
Logger::println("D to dwarf stoppoint at line %u", ln);
|
||||
LOG_SCOPE;
|
||||
llvm::DebugLoc loc = llvm::DebugLoc::get(ln, 0, GetCurrentScope());
|
||||
IR->ir->SetCurrentDebugLocation(loc);
|
||||
}
|
||||
|
||||
void ldc::DIBuilder::EmitValue(llvm::Value *val, VarDeclaration *vd)
|
||||
{
|
||||
if (!global.params.symdebug || !vd->debugVariable)
|
||||
return;
|
||||
|
||||
llvm::Instruction *instr = DBuilder.insertDbgValueIntrinsic(val, 0, vd->debugVariable, IR->scopebb());
|
||||
instr->setDebugLoc(IR->ir->getCurrentDebugLocation());
|
||||
}
|
||||
|
||||
void ldc::DIBuilder::EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd,
|
||||
llvm::ArrayRef<llvm::Value *> addr)
|
||||
{
|
||||
if (!global.params.symdebug)
|
||||
return;
|
||||
|
||||
Logger::println("D to dwarf local variable");
|
||||
LOG_SCOPE;
|
||||
|
||||
if (IR->func()->diSubprogram == vd->debugFunc) // ensure that the debug variable is created only once
|
||||
return;
|
||||
|
||||
// get type description
|
||||
llvm::DIType TD = CreateTypeDescription(vd->type, NULL, true);
|
||||
if (static_cast<llvm::MDNode *>(TD) == 0)
|
||||
return; // unsupported
|
||||
|
||||
// get variable description
|
||||
assert(!vd->isDataseg() && "static variable");
|
||||
|
||||
unsigned tag;
|
||||
if (vd->isParameter())
|
||||
tag = llvm::dwarf::DW_TAG_arg_variable;
|
||||
else
|
||||
tag = llvm::dwarf::DW_TAG_auto_variable;
|
||||
|
||||
if (addr.empty()) {
|
||||
vd->debugVariable = DBuilder.createLocalVariable(
|
||||
tag, // tag
|
||||
GetCurrentScope(), // scope
|
||||
vd->toChars(), // name
|
||||
CreateFile(vd->loc), // file
|
||||
vd->loc.linnum, // line num
|
||||
TD, // type
|
||||
true // preserve
|
||||
);
|
||||
} else {
|
||||
vd->debugVariable = DBuilder.createComplexVariable(
|
||||
tag, // tag
|
||||
GetCurrentScope(), // scope
|
||||
vd->toChars(), // name
|
||||
CreateFile(vd->loc), // file
|
||||
vd->loc.linnum, // line num
|
||||
TD, // type
|
||||
addr
|
||||
);
|
||||
}
|
||||
vd->debugFunc = IR->func()->diSubprogram;
|
||||
|
||||
// declare
|
||||
Declare(ll, vd->debugVariable);
|
||||
}
|
||||
|
||||
llvm::DIGlobalVariable ldc::DIBuilder::EmitGlobalVariable(llvm::GlobalVariable *ll, VarDeclaration *vd)
|
||||
{
|
||||
if (!global.params.symdebug)
|
||||
return llvm::DIGlobalVariable();
|
||||
|
||||
Logger::println("D to dwarf global_variable");
|
||||
LOG_SCOPE;
|
||||
|
||||
assert(vd->isDataseg() || (vd->storage_class & (STCconst | STCimmutable) && vd->init));
|
||||
|
||||
return DBuilder.createGlobalVariable(
|
||||
vd->toChars(), // name
|
||||
#if LDC_LLVM_VER >= 303
|
||||
vd->mangle(), // linkage name
|
||||
#endif
|
||||
CreateFile(vd->loc), // file
|
||||
vd->loc.linnum, // line num
|
||||
CreateTypeDescription(vd->type, NULL), // type
|
||||
vd->protection == PROTprivate, // is local to unit
|
||||
ll // value
|
||||
);
|
||||
}
|
||||
|
||||
void ldc::DIBuilder::EmitModuleEnd()
|
||||
{
|
||||
if (!global.params.symdebug)
|
||||
return;
|
||||
|
||||
DBuilder.finalize();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue